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.
Related
why gcc 9.4 not check parameters when bind a class member funtion to a std::function viriable, but check when bind a global function? here is example code, CreateRpcFun has a parameter, but Test member function print doesn't have any other parameters except this, bind print to CreateRpcFun works well, but global funtion print2 cannot, can anybody explain why?
#include <functional>
#include <iostream>
#include <string>
using namespace std;
using CreateRpcFun = std::function<void(const string &)>;
class Test {
public:
Test() : str_("nihao!") {}
// bind print to CreateRpcFun passed compile
void print() { cout << str_ << endl; }
private:
string str_;
};
class Holder {
public:
CreateRpcFun CreateRpc;
};
class Other {
public:
Other(Holder h, string str) : h_(h), str_(str) {}
void run() { h_.CreateRpc("world!"); }
private:
Holder h_;
string str_;
};
void print1(const string &str) { cout << str << endl; }
void print2() { cout << "magic" << endl; }
int main() {
Test t;
Holder h;
h.CreateRpc = std::bind(&Test::print, &t);
Other o(h, "hhhh");
o.run();
h.CreateRpc = &print1;
h.CreateRpc("test");
// h.CreateRpc = &print2; // compile error
// h.CreateRpc("test");
}
I am trying to write a class which defines a std::map. The comparator of the map must be a function pointer. The function pointer can be passed to the class as an argument in class's constructor.
Below is the code I wrote:
#include <iostream>
#include <map>
#include <string>
#include <functional>
typedef std::function<bool(std::string x, std::string y)> StrComparatorFn;
bool FnComparator(std::string x, std::string y) {
return strtoul(x.c_str(), NULL, 0) < strtoul(y.c_str(), NULL, 0);
}
class MyClass {
public:
MyClass(StrComparatorFn fptr):fn_ptr(fptr){};
void Insert() {
my_map.insert(std::pair<std::string, std::string>("1", "one"));
my_map.insert(std::pair<std::string, std::string>("2", "two"));
my_map.insert(std::pair<std::string, std::string>("10", "ten"));
}
void Display() {
for (auto& it : my_map) {
std::cout << it.first.c_str() << "\t => " << it.second.c_str() << "\n";
}
}
private:
StrComparatorFn fn_ptr;
std::map<std::string, std::string, StrComparatorFn> my_map(StrComparatorFn(fn_ptr));
};
int main() {
MyClass c1(&FnComparator);
c1.Insert();
c1.Display();
}
I am getting a compile error in Insert:
error: '((MyClass*)this)->MyClass::my_map' does not have class type
my_map.insert(std::pair<std::string, std::string>("1", "one"));
Any solution to this issue?
That line
std::map<std::string, std::string, StrComparatorFn> my_map(StrComparatorFn(fn_ptr));
has a problem known as the most vexing parse. Basically, everything that can be interpreted as a function, will be:
Foo f(); //f is a function! Not a variable
In your case, my_map is parsed as a declared function without a definition. Using curly braces instead of curved braces will solve the problem, as list initialization can never be interpreted as a function:
std::map<std::string, std::string, StrComparatorFn> my_map{ StrComparatorFn(fn_ptr) };
#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));
I have made a map of functions. all these functions are void and receive single string parameter.
code:
void f1(string params){...}
void f2(string params){...}
void f3(string params){...}
map<string , void*> funcMap;
funcMap["f1"] =(void*)&f1;
funcMap["f2"] =(void*)&f2;
funcMap["f3"] =(void*)&f3;
how do i call a function?
I tried the next code, but id doesn't work:
void (*func)(string) = &funcMap[commandType];
func(commandParam);
I get this error message:
Server.cpp:160:46: error: cannot convert ‘void**’ to ‘void (*)(std::string) {aka void (*)(std::basic_string<char>)}’ in initialization
using pfunc = void (*)(string);
map<string, pfunc> funcMap;
funcMap["f1"] = f1; //and so forth
And then call:
pfunc f = funcMap[commandType];
(*f)(commandParam);
In general, why throw away type safety? If it's a map of function pointers, declare it to be one.
Why not just have those as separate classes.
Then have the methods as virtual.
You can then have a map between the string and the base class.
i.e.
class Someoperation
{
virtual void Doit() = 0;
};
map<string, Someopertion> ops;
Then
class MyOp : public Someoperation
{
void Doit() { /* Some code here */}
};
Just add objects
ops["Hello"] = MyOp();
then call it
ops["Hello"].Doit();
&funcMap[commandType]
Just drop the &. Your compile error was useful here. It had a void** on the right which is because you took the address of a function pointer. You don't want two levels of indirection there.
Try C++ style. It has overhead for allocation and inheritance, but it's more flexible and extensible if you'll need some more functionality in the future.
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
using namespace std;
class Someoperation {
public:
virtual void Doit() = 0;
};
class MyOp1 : public Someoperation {
public:
void Doit() final { cout << "MyOp1" << endl; }
};
class MyOp2 : public Someoperation {
public:
void Doit() final { cout << "MyOp2" << endl; }
};
int main() {
unordered_map<string, unique_ptr<Someoperation> > ops;
ops["1"] = unique_ptr<Someoperation>(new MyOp1);
ops["2"] = unique_ptr<Someoperation>(new MyOp2);
ops["1"]->Doit(); // Out: MyOp1
ops["2"]->Doit(); // Out: MyOp2
return 0;
}
#include <boost/bind.hpp>
#include <iostream>
using namespace std;
using boost::bind;
class A {
public:
void print(string &s) {
cout << s.c_str() << endl;
}
};
typedef void (*callback)();
class B {
public:
void set_callback(callback cb) {
m_cb = cb;
}
void do_callback() {
m_cb();
}
private:
callback m_cb;
};
void main() {
A a;
B b;
string s("message");
b.set_callback(bind(A::print, &a, s));
b.do_callback();
}
So what I'm trying to do is to have the print method of A stream "message" to cout when b's callback is activated. I'm getting an unexpected number of arguments error from msvc10. I'm sure this is super noob basic and I'm sorry in advance.
replace typedef void (*callback)(); with typedef boost::function<void()> callback;
A bound function doesn't produce an ordinary function, so you cannot just store it in a regular function pointer. However, boost::function is able to handle anything as long as it is callable with the correct signature, so that's what you want. It will work with a function pointer, or a functor created with bind.
After a few corrections to your code, I came up with this:
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
// i prefer explicit namespaces, but that's a matter of preference
class A {
public:
// prefer const refs to regular refs unless you need to modify the argument!
void print(const std::string &s) {
// no need for .c_str() here, cout knows how to output a std::string just fine :-)
std::cout << s << std::endl;
}
};
// holds any arity 0 callable "thing" which returns void
typedef boost::function<void()> callback;
class B {
public:
void set_callback(callback cb) {
m_cb = cb;
}
void do_callback() {
m_cb();
}
private:
callback m_cb;
};
void regular_function() {
std::cout << "regular!" << std::endl;
}
// the return type for main is int, never anything else
// however, in c++, you may omit the "return 0;" from main (and only main)
// which will have the same effect as if you had a "return 0;" as the last line
// of main
int main() {
A a;
B b;
std::string s("message");
// you forget the "&" here before A::print!
b.set_callback(boost::bind(&A::print, &a, s));
b.do_callback();
// this will work for regular function pointers too, yay!
b.set_callback(regular_function);
b.do_callback();
}