C++ Passing a class method as function pointer - c++

I have a class that has to process data from various files. I thought about creating one function that will read the specified file and then also accept a call back so that it can use that to process the line. Below is an example class to represent what I am trying to do:
#include <iostream>
#include <vector>
#include <string>
class Example
{
std::vector<std::string> m_exampleFileData {
"test1",
"test2",
"test3"
};
public:
void doSomethingMain(const std::string& path)
{
processFile(path, doSomething);
}
private:
void processFile(const std::string& filePath, void (Example::*fpProcessLine)(const std::string&) )
{
for (const auto& line : m_exampleFileData) {
this->*fpProcessLine(line);
}
}
void doSomething(const std::string& line)
{
std::cout << "Hello: " << line << '\n';
}
};
int main(int argc, char** argv) {
const std::string filePath{"path"};
Example ex;
ex.doSomethingMain(filePath);
}
Compiler explorer: https://godbolt.org/z/LKoXSZ
The main issue is that no matter what I do I can't seem to be able to pass the function properly to processFile. Is there a way to do this in C++? How do I go about this?

You need to spell things out explicitly, in this situation:
processFile(path, &Example::doSomething);
Furthermore, you also need to slap on an extra pair of parenthesis, due to operator precedence:
(this->*fpProcessLine)(line);

Related

How to create a class that stores pointers to member functions (C++)

I'm trying to create a class that stores pointers to member functions of other classes and that can be executed from a text command (like a game console).
I did something functional, based on an example found here, that stores members with string-like input. Below is my implementation.
file: Command.hpp
#include <string>
#include <functional>
#include <unordered_map>
#include <string>
#include <iostream>
using namespace std;
class Command
{
public:
Command();
virtual ~Command();
void RegisterCommand(string command, function<void(const string&)> fun);
void Run(const string& command, const string& arg);
private:
unordered_map<string, function<void(const string&)>> functions;
};
file: Command.cpp
Command::Command()
{
}
Command::~Command()
{
}
void Command::RegisterCommand(string command, function<void(const string&)> fun)
{
functions[command] = fun;
}
void Command::Run(const string& command, const string& arg)
{
functions[command](arg);
}
file: main.cpp
#include "Command.hpp"
// function to register
void xyz_fun(const string& commandLine)
{
cout << "console output: " << commandLine << endl;
}
int main(int argc, char* argv[])
{
Command m_Cmd;
// Register function
m_Cmd.RegisterCommand("xyz_fun", xyz_fun);
// Run registered function
m_Cmd.Run("xyz_fun", "hello world.");
return EXIT_SUCCESS;
}
My question is how to implement a generic class to store members with unknown input arguments (Booleans, integers, doubles, strings, etc.).
For example, I could do:
m_Cmd.RegisterCommand("xyz_fun2", xyz_function2);
and call
m_Cmd.Run("xyz_fun2", false)
which has a boolean argument instead of a string.
Thanks in advance for your attention and any help is welcome.
Instead of
unordered_map<string, function<void(const string&)>> functions;
you could do
union acceptable_types { int i; char c; bool b; std::string* s; ... };
unordered_map<string, function<void(acceptable_types)>> functions;
Then when calling functions, just place the value wanted by the function into a variable of type acceptable_types.
If a function is wants to use a specific value, it should just use a specific member of the acceptable_types union.
Here's an example:
#include "Command.hpp"
void
my_bool_func (acceptable_types union_param)
{
bool bool_var = union_param.b;
// ...
// Use bool_var
// ...
}
void
my_string_func (acceptable_types union_param)
{
std::string string_var = *(union_param.s);
// ...
// Use string_var
// ...
}
int
main(int argc, char* argv[])
{
Command my_command;
acceptable_types union_var;
my_command.RegisterCommand("my_bool_func", my_bool_func);
my_command.RegisterCommand("my_string_func", my_string_func);
union_var.b = true;
my_command.Run("my_bool_func", union_var);
*(union_var.s) = "hello world.";
my_command.Run("my_string_func", union_var);
return 0;
}

How do I redefine a class's function outside of the class

class Function
{
public:
std::string Name;
void call(std::string x);
Function(std::string Nam)
{
Name = Nam;
}
};
std::vector<Function> funcs;
void Load_FuncLib()
{
Function print("print");
Function add("add");
print.call(std::string x)
{
std::cout<< x <<"\n";
}
add.call(std::string x)
{
std::cout<< std::stoi(x) + std::stoi(x) << "\n";
}
funcs.push_back(print);
funcs.push_back(add);
funcs.at(0).call("Hello world");
}
I want it to run the function print.call("Hello world"); but it will not work as I don't know how to set a function, which is already declared, nor do I know how to call it using a vector.
You most likely want to achieve something like this?
#include <unordered_map>
#include <iostream>
#include <string>
#include <functional>
int main() {
std::unordered_map<std::string, std::function<void (const std::string&)>> funcs;
funcs["print"] = [](const std::string& str) {
std::cout << str << '\n';
};
funcs["add"] = [](const std::string& str) {
int i = std::stoi(str);
std::cout << i + i << '\n';
};
funcs["print"]("Hello, World!");
funcs["add"]("12");
}
https://ideone.com/Ke4aEK
At any time you can reset a certain value of the hash map with another function.
Also, depending on your needs, you may use std::function or just plain function pointers.

Passing a generic template parameter from a map?

I am coming from c# so please excuse anything I may get wrong in trying to ask this question.
I have created a map that contains a string and a method to handle invoking a method by a string:
//MyClass.h
void SerializeCustomData();
std::unordered_map<std::string, void(MyClass::*)()> functionMap;
MyMethod() {
functionMap["SerializeCustomData"] = &MyClass::SerializeCustomData;
};
My question is; how can I have my map take in a parameter for the method? Either a generic type or a string in c++?
Example:
SerializeCustomData(std::string);
#include <functional>
#include <iostream>
#include <unordered_map>
class MyClass
{
std::unordered_map<std::string, std::function<void(MyClass&, std::string)>> functionMap;
public:
void MyMethod()
{
functionMap.emplace("SerializeCustomData", &MyClass::SerializeCustomData);
}
void CallSerialize()
{
functionMap.at("SerializeCustomData")(*this, "argument");
}
void SerializeCustomData(std::string s)
{
std::cout << "hello: " << s << "\n";
}
};
int main()
{
MyClass c;
c.MyMethod();
c.CallSerialize();
}
Here the function from the map is called with a MyClass& argument and a string. Note that the MyClass isn't bound to the callback, and so we're passing it explicitly.

C++ Passing vectors to an overloaded class - some call statements work, some do not.

I have spent a great deal of time in google trying to figure out how to pass a vector when using .h and .cpp files between a call in main and a function in an includes block. I was successful using class definitions.
Now everything is going fine until I want to create an overloaded function. (I could have done this with two different classes, but I must use one overloaded function in my program.)
Here is my writeData.h file:
#ifndef WRITEDATA_H
#define WRITEDATA_H
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
class writeData
{
public: writeData();
public: writeData(vector<int> & DATAFILE);
public: writeData(vector<int> & DATAFILE, string);
};
#endif
The placement of the using namespace std; is another topic.
Here is my writeData.cpp file:
#include "writeData.h"
writeData::writeData()
{
std::cout << "Default writeData" << std::endl;
}
writeData::writeData(vector<int> & DATAFILE)
{
cout << "writeData 1" << endl;
for (int var : DATAFILE)
{
cout << var <<endl;
}
}
writeData::writeData(vector<int> & DATAFILE, string fileName)
{
ofstream myfile(fileName);
cout << "writeData" << endl;
if (myfile.is_open())
{
for (int var : DATAFILE)
{
cout << var << endl;
myfile << var << endl;
}
myfile.close();
}
}
And here is my main function:
#include <iostream>
#include <vector>
#include <string>
#include "writeData.h"
using namespace std;
int main()
{
string fileName = "test.txt";
vector<int> items{ 10, 14, 22, 34 };
writeData();//default
///////////////////////////////////////////////////
// the next line is the problem code:
//writeData(items);//writes to screen only
//<<When I uncomment it the compiler Tosses the following:
// 'items': redefinition; different basic types
////////////////////////////////////////////////////
writeData(items, fileName);//writes to screen and to file
cin.ignore();
cin.get();
}
The offending line is writeData(items);
Any assistance or pointers to online articles would be most appreciated.
The immediate issue is that this declaration
writeData(items);
is the same as
writeData items;
hence the redefinition error. The deeper issue is that you have defined three constructors for a class, and seem to be attempting to call them without making a named instance. To succesfully call the one parameter constructor passing items, you'd need something like
writeData data_writer(items);
Alternatively, you may want either member functions, or non-members. The choice would depend on whether you really want to model a class, which maintains certain invariants or not. An example of members,
class writeData
{
public:
void write_data() const;
void write_data(const vector<int> & DATAFILE) const;
void write_data(const vector<int> & DATAFILE, string) const;
};
Then
WriteData wd;
wd.write_data(items);
Example of non-members:
namespace writeData
{
void write_data();
void write_data(const vector<int> & DATAFILE);
void write_data(const vector<int> & DATAFILE, string);
};
Then
writeData::write_data(items);
Note I have made the vector<int> parameters const reference because they are not being moified in the functions.

cannot call member function without object for vector of shared_ptr of object

#include <boost/ref.hpp>
//#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/mem_fn.hpp>
using namespace std;
using namespace boost::lambda;
class Base {
public:
Base () {}
bool toBeRemoved() const {
return true;
}
};
class status : public Base {
std::string name_;
bool ok_;
public:
status(const std::string& name):name_(name),ok_(true) {}
void break_it() {
ok_=false;
}
bool is_broken() const {
return ok_;
}
void report() const {
std::cout << name_ << " is " <<
(ok_ ? "working nominally":"terribly broken") << '\n';
}
std::string getStatus() const {
return ok_ ? "1" : "0";
}
};
class some_class {
public:
int test() {
std::vector<boost::shared_ptr<status> > s_statuses = getStatus(); //some func
std::set<string> s;
std::transform(s_statuses.begin(), s_statuses.end(), std::inserter(s, s.begin()), boost::lambda::bind(boost::mem_fn(&status::getStatus), boost::ref(*_1)));
// approach #2
// std::transform(s_statuses.begin(), s_statuses.end(), std::inserter(s, s.begin()), boost::lambda::bind(boost::mem_fn(&status::getStatus), boost::ref(*_1), _1));
// approach #3
// std::transform(s_statuses.begin(), s_statuses.end(), std::inserter(s, s.begin()), boost::bind(&status::getStatus), _1));
std::copy(s.begin(), s.end(), ostream_iterator<string>(std::cout, "-"));
std::cout << endl;
return 0;
}
}
For all the approaches above, I am getting the error "can call member function without object" on the line containing the bind call. I have tried using boost::lambda::bind and boost::bind as well. Though this way of using bind works if objects are defined, for example in main function. I assume I am making some silly mistake here, but I am not able to figure out why these all approaches working, or it could be the case that this is not the right way of doing at all.
Could someone please help me resolve this on how to properly use boost bind for non-static member of class which are stored in stl containers ?
Thanks,
You should just need to use boost::mem_fn. (Note, you could also use std::mem_fn if available.)
std::transform(s_statuses.begin(), s_statuses.end(), std::inserter(s, s.begin()), std::mem_fn(&status::getStatus));