Call method by string and pass arguments - c++

i search for a way to call a method by its string name.
#include <iostream>
#include <string>
class myClass{
public:
void method1(int run){
std::cout << run << std::endl;
}
void method2(int run){
std::cout << run << std::endl;
}
};
int main(){
myClass mc;
std::string call;
call = "method1";
mc.call(1);
call = "method2";
mc.call(2);
}
But the result, is
‘class Myclass’ has no member named ‘call’
I need response "1" and "2";
EDIT :: Very thank's for your help, i get the next solution (i don't know is good for all cases );
#include <iostream>
#include <string>
class myClass{
public:
void method1(int run){
std::cout << "Loaded method => " << run << std::endl;
}
void method2(int run){
std::cout << "Loaded method => " << run << std::endl;
}
void _loadMethods(int method, int params){
switch(method) {
case 1:
method1(params);
break;
case 2:
method2(params);
break;
default:
break;
}
}
};
int main(){
myClass mc;
std::string method;
method = "method2";
if(method == "method1"){
mc._loadMethods(1, 1);
}
if(method == "method2"){
mc._loadMethods(2, 2);
}
}
Thank's

This is not possible in "raw" C++. But... What you are trying to achieve is some kind of Reflection or Class meta-type information.
You can look at this project: http://www.axelmenzel.de/projects/coding/rttr , use Qt: http://doc.qt.io/qt-5/qmetatype.html#details or google for C++ reflection.

Related

How to map functions of a class using std::map in the same class? (Error C3867) [duplicate]

This question already has answers here:
How to initialize `std::function` with a member-function?
(3 answers)
Using generic std::function objects with member functions in one class
(6 answers)
Closed 25 days ago.
I'm trying to make a program to have a string input for choosing functions.
My code is as follows:
#include <iostream>
#include <map>
#include <functional>
#include <string>
std::map<std::string, std::function<void(bool)>>functions;
void command_greet(bool new_input);
void command_add(bool new_input);
void command_help(bool new_input);
void commands()
{
functions["hi"] = command_greet; //command
functions["add"] = command_add; //command
functions["help"] = command_help; //command
}
void command_greet(bool new_input)
{
if (new_input)
{
std::cout << "Hello!" << std::endl;
}
else
{
std::cout << "This command greets!\n";
}
}
void command_add(bool new_input)
{
if (new_input)
{
int x, y;
std::cout << "X: ";
std::cin >> x;
std::cout << "\nY: ";
std::cin >> y;
std::cout << "\n" << x + y << "\n";
std::cin.ignore();
}
else
{
std::cout << "This command adds two numbers!\n";
}
}
void command_help(bool new_input)
{
if (new_input)
{
size_t cmd_len = 0;
for (const auto& elem : functions) //calculate length of the longest command
{
if (elem.first.size() > cmd_len)
{
cmd_len = elem.first.size();
}
}
cmd_len += 4; //length plus 4 spaces
for (const auto& elem : functions)
{
std::cout << elem.first;
for (size_t i = 0; i < cmd_len - elem.first.size(); i++)
{
std::cout << ' ';
}
elem.second(false); //command description
}
}
else
{
std::cout << "This command shows commands list!\n";
}
}
int main()
{
commands();
std::string input;
while (true) //endless loop for testing
{
std::cout << "Input: ";
std::getline(std::cin, input);
if (functions.count(input) > 0)
{
functions.find(input)->second(true); //run command
std::cout << std::endl;
}
else if (input == "")
{
}
else
{
std::cerr << "'" << input << "' was not recognized.\n"
<< "Type 'help' for available commands.\n";
std::cout << std::endl;
}
}
return 0;
}
The code above works fine with no problems.
Now I want to convert it to class instead of having "bare" functions.
What I've tried:
Partial contents of cmd_console.h
#ifndef __CMD_CONSOLE__
#define __CMD_CONSOLE__
#include <iostream>
#include <string>
#include <map>
#include <functional>
class cmd_console
{
private:
std::map<std::string, std::function<void(bool)>>m_commands;
public:
cmd_console();
void cmd_logic(std::string new_input);
//...other methods here...
~cmd_console();
private:
void commands_inicialise();
//...other methods here...
void command_help(bool new_input);
//...command methods here...
void command_exit(bool new_input);
};
#endif
Partial contents of cmd_console.cpp
#include "cmd_console.h"
cmd_console::cmd_console()
{
commands_inicialise();
}
void cmd_console::commands_inicialise()
{
m_commands["HELP"] = command_help;
//Error C3867: non-standard syntax; use '&' to create a pointer to member
m_commands["EXIT"] = command_exit;
//Error C3867: non-standard syntax; use '&' to create a pointer to member
}
//...other methods here...
void cmd_console::command_help(bool new_input)
{
//code here
}
//...command methods here...
void cmd_console::command_exit(bool new_input)
{
//code here
}
cmd_console::~cmd_console()
{
}
The problem is here:
m_commands["HELP"] = command_help;
//Error C3867: non-standard syntax; use '&' to create a pointer to member
I'm unable to solve this even that it seems to be simple.
Anyone have an idea how to make it work? Thank you.

Does the stream operator exist for class member functions?

I included the logger from boost. I'm pretty pleased how it works. Just for simplicity and the reason I don't want to use makros to often in my code, I wrap it in a class.
I now wonder if I could use the streaming operator << to write on a member function.
code
class LogWrapper{
...
//debug function
//info function
...
}
void main() {
LogWrapper log;
log.debug() << "some debug msg"; // does this exist?
log.info() << "some info msg";
}
output
[some_timestamp][debug] some debug msg
[some_timestamp][info] some info msg
Is this possible in a good practice, or is it entirely bad style?
It can be done easily like this:
#include <iostream>
class A {
public:
std::ostream &debug() const {
std::cerr << "[timestamp]" << "[DEBUG]";
return std::cerr;
}
};
int main()
{
A a;
a.debug() << "Test";
}
But the important question here is: Should we implement it in this way? In my opinion, NO!
Because you are thinking that the User of the class will print the logs like this:
int main()
{
A a;
a.debug() << "Test" << std::endl;
a.debug() << "Test2" << std::endl;
}
Output:
[timestamp][DEBUG]Test
[timestamp][DEBUG]Test2
But what if User chooses this way:
int main()
{
A a;
auto &out = a.debug();
out << "Test" << std::endl;
out << "Test2" << std::endl;
}
Output:
[timestamp][DEBUG]Test
Test2
I would highly recommend not to return stream object. You should use member functions for this purpose.
#include <iostream>
class A {
public:
static void debug(const std::string &log) {
std::cerr << "[timestamp]" << "[DEBUG]" << log << std::endl;
}
};
int main()
{
A::debug("Test 1");
A::debug("Test 2");
}
Output:
[timestamp][DEBUG]Test 1
[timestamp][DEBUG]Test 2

Cannot instantiate abstract class?

I got this:
class Core
{
protected:
static unsigned int id_seed;
unsigned int id;
std::string status;
public:
friend class CPU;
Core();
~Core();
virtual void procesare(std::string aplicatie) = 0;
};
class CoreScreen: public Core
{
public:
CoreScreen();
~CoreScreen();
void procesare(std::string aplicatie);
};
and corescreen.cpp:
#include "CoreScreen.h"
CoreScreen::CoreScreen()
{
}
CoreScreen::~CoreScreen()
{
}
void CoreScreen::procesare(std::string aplicatie)
{
std::string buffer;
std::ifstream file_in(aplicatie);
if (file_in.is_open()) {
std::cout << "Aplicatia " << aplicatie << " ruleaza: " << std::endl;
while (getline(file_in, buffer)) {
std::cout << buffer;
}
file_in.close();
}
else {
throw new CExceptie(APP_FAIL, " Aplicatia nu a putut rula!");
}
}
When I use in main:
CoreScreen CS1, CS2, CS3, CS4;
I get this error: 'Core' cannot instantiate abstract class.
What's the problem? I thought I have my virtual function declared in CoreScreen correctly.
As I presume you know, "Core" is an abstract class, by virtue of the fact it has a pure virtual function: virtual void procesare(std::string aplicatie) = 0;.
I presume you also know that you can't instantiate an abstract class: hence your error.
The question is:
Why does the compiler think you're trying to instantiate an instance of "Core"?
Are you?
It looks like you're trying to instantiate four CoreScreen objects: CoreScreen CS1, CS2, CS3, CS4;. If so, that should be perfectly OK.
You're correct: procesare() is virtual ("pure virtual", as it happens). You've indeed overridden it correctly in CoreScreen.cpp: it DOESN'T look like that's the problem.
Q: Did you ever implement Core::Core() and Core::~Core() anywhere? If not, how did you even compile?
Q: Are you SURE you're not trying to create an instance of "Core" anywhere (even "accidentally")?
For whatever it's worth, the following MCVE compiles and runs fine (Ubuntu 18, GCC 7.3.0):
TestCore.h:
/*
* TestCore.h
*/
#ifndef TESTCORE_H_
#define TESTCORE_H_
#include <string>
class Core
{
protected:
static unsigned int id_seed;
unsigned int id;
std::string status;
public:
friend class CPU;
Core();
~Core();
virtual void procesare(std::string aplicatie) = 0;
};
class CoreScreen: public Core
{
public:
CoreScreen();
~CoreScreen();
void procesare(std::string aplicatie);
};
#endif /* TESTCORE_H_ */
TestCore.cpp:
/*
* TestCore.cpp
*/
#include <iostream>
#include <fstream>
#include "TestCore.h"
Core::Core()
{
std::cout << "Core::Core()..." << std::endl;
}
Core::~Core()
{
std::cout << "Core::~Core()..." << std::endl;
}
CoreScreen::CoreScreen()
{
std::cout << "CoreScreen::CoreScreen()..." << std::endl;
}
CoreScreen::~CoreScreen()
{
std::cout << "CoreScreen::~CoreScreen()..." << std::endl;
}
void CoreScreen::procesare(std::string aplicatie)
{
std::cout << "CoreScreen::procesare(" << aplicatie << ")" << std::endl;;
}
int main () {
std::cout << ">>main()..." << std::endl;
CoreScreen CS1, CS2, CS3, CS4;
CS1.procesare("Testing CS1");
std::cout << "<<main()." << std::endl;
return 0;
}
SAMPLE OUTPUT:
>>main()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
CoreScreen::procesare(Testing CS1)
<<main().
You'll note that I implemented Core::Core() and Core::~Core(). If you don't need them - then don't even put them in your .h class definition.
'Hope that helps

"undefined identifier" despite defining it in the class.

im a beginner in c++ and i am so confused why i am getting an error in my code, could you guys please tell me whats going wrong? im using visual studios 2017.
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
class Cat {
private:
bool happy;
public:
void speak() {
cout << "meow" << endl;
}
Cat() {
bool newHappy = happy;
happy = true;
}
};
int main()
{
cout << "Starting program..." << endl;
Cat bob;
bob.speak();
if (happy) {
cout << "cat is happy" << endl;
}
else {
cout << "unhappy cat" << endl;
}
cout << "Ending program..." << endl;
return 0;
}
You're trying to reference a variable called happy inside your main function, which doesn't exist in that scope. If you want to see if bob is happy, you could simply write if (bob.happy){ ... and change Cat::happy from private to public, or you could create a getter function like:
class Cat {
private:
bool happy;
public:
bool isHappy() const {
return happy;
}
...
};
and call the function as follows: if (bob.isHappy()){ ...

elegant method to pass the data type for `boost::variant`

I need to find a better solution to pass the data type into boost::variant so that the function can retrieve the stored variate type elegantly. I have put up an implementation that works for me but I am concern there is a better way out there.
// file name: p192.cpp
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
using namespace std;
enum TypePassIn
{
INT_TYPE,
DOUBLE_TYPE,
STRING_TYPE,
PERSON_TYPE,
LAST_TYPE = PERSON_TYPE
};
struct Person
{
Person(int _age, string _name) : age(_age), name(_name) {}
int age;
string name;
};
void PrintVariant(map<string, boost::variant<int, double, string, Person> > _mapValues, TypePassIn tpi)
{
switch(tpi)
{
case INT_TYPE:
cout << boost::get<int>(_mapValues["int"]) << endl;
break;
case DOUBLE_TYPE:
cout << setprecision (15) << boost::get<double>(_mapValues["double"]) << endl;
break;
case STRING_TYPE:
cout << boost::get<string>(_mapValues["string"]) << endl;
break;
case PERSON_TYPE:
cout << "Age: " << (boost::get<Person>(_mapValues["Person"])).age;
cout << ", Name: " << (boost::get<Person>(_mapValues["Person"])).name << endl;
break;
default:
break;
}
}
int main(void)
{ map<string, boost::variant<int, double, string, Person> > mapValues;
mapValues["int"] = 10;
PrintVariant(mapValues, INT_TYPE);
mapValues["double"] = 100.99;
PrintVariant(mapValues, DOUBLE_TYPE);
mapValues["string"] = "Hello world";
PrintVariant(mapValues, STRING_TYPE);
mapValues["Person"] = Person(10, "Tom");
PrintVariant(mapValues, PERSON_TYPE);
}
~/Documents/C++/boost $ ./p192
10
100.99
Hello world
Age: 10, Name: Tom
As you can see from the code above, the implemented method can handle both native type and customized data type. In the ideal case, we can do it without introducing the enum TypePassIn
You can use the (static) visitor pattern, as shown in the tutorial of Boost.Variant.
struct VariantPrinter : boost::static_visitor<void>
{
void operator()(int int_val)
{
std::cout << int_val << std::endl;
}
void operator()(double double_val)
{
std::cout << std::setprecision(15) << double_val << std::endl;
}
// etc.
};
void PrintVariant(const boost::variant<...>& the_variant)
{
boost::apply_visitor(VariantPrinter(), the_variant);
}
int main()
{
std::map<std::string, boost::variant<...> > mapValues;
mapValues["int"] = 10;
PrintVariant(mapValues["int"]);
}