I need to bind one parameter to class member function.
Something like this:
#include <functional>
#include <iostream>
struct test
{
void func(int a, int b)
{
std::cout << a << " " << b << std::endl;
}
};
int main(int argc, char** argv)
{
typedef void (test::*TFunc)(int);
TFunc func = std::bind(&test::func, 1, std::placeholders::_1);
}
But in this case I have compilation error
error: static assertion failed: Wrong number of arguments for pointer-to
-member
std::bind does not yield a member function pointer, but it can produce a std::function object that you can use later:
::std::function< void (test *, int)> func = std::bind(&test::func, std::placeholders::_1, 1, std::placeholders::_2);
test t{};
func(&t, 2);
Related
Recently I was reading about variadic templates and based on an example I've seen online I was trying to implement a basic event-system. So far it seems to work fine but I was trying to go a step further and allow N number of arguments to be passed to an event handler function / callback, unfortunately the build error I'm getting is the following and I'm not sure what I'm doing wrong. I looked into similar source codes but still cant figure out what's the issue.
D:\Development\lab\c-cpp\EventEmitter3\src\main.cpp:30:68: error: parameter packs not expanded with '...':
return std::any_cast<std::function<R(Args)>>(eventCallback)(std::forward<Args>(args)...);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
D:\Development\lab\c-cpp\EventEmitter3\src\main.cpp:30:68: note: 'Args'
Build finished with error(s).
Here is what I have so far, if you remove the ... the event system works fine for the 2 registered events in main.
#include <any>
#include <string>
#include <iostream>
#include <functional>
#include <unordered_map>
class EventEmitter
{
private:
std::unordered_map<std::string, std::any> events;
public:
EventEmitter() {}
void on(const std::string &eventName, const std::any &eventCallback)
{
events[eventName] = eventCallback;
}
template <typename R>
R emit(const std::string &eventName)
{
const std::any &eventCallback = events[eventName];
return std::any_cast<std::function<R(void)>>(eventCallback)();
}
template <typename R, typename... Args>
R emit(const std::string &eventName, Args &&...args)
{
const std::any &eventCallback = events[eventName];
return std::any_cast<std::function<R(Args)>>(eventCallback)(std::forward<Args>(args)...);
}
virtual ~EventEmitter() {}
};
int fun1()
{
std::cout << "fun1" << std::endl;
return 1;
}
double fun2(int i)
{
std::cout << "fun2" << std::endl;
return double(i);
}
double fun3(int x, int y)
{
std::cout << "fun3" << std::endl;
return double(x + y);
}
int main(int argc, char *argv[])
{
EventEmitter e;
e.on("fun1", std::function<int(void)>(fun1));
e.on("fun2", std::function<double(int)>(fun2));
e.emit<int>("fun1");
e.emit<double, int>("fun2", 1);
// Variadic would have been handy right here I guess?
// e.on("fun3", std::function<double(int, int)>(fun3));
// e.emit<double, int>("fun3", 1, 2);
return 0;
}
How can I fix this?
Well, you need to expand it.
return std::any_cast<std::function<R(Args...)>>(eventCallback)(std::forward<Args>(args)...);
^^^^^^^
I need a function that generates other functions. Why doesn't the following not let me convert a lambda to a std::function? I've done that before.
#include <iostream>
#include <functional>
std::function<int()> funcGen(int param) {
std::function<int()> myGeneratedFunc =
[param](int input) -> int {
return input+param;
};
return myGeneratedFunc;
}
int main() {
std::function<int()> myFunc = funcGen(3);
std::cout << "this should be 4=3+1: " << myFunc(1) << "\n";
return 0;
}
On ideone I get the following error:
error: conversion from ‘funcGen(int)::<lambda(int)>’ to non-scalar type ‘std::function<int()>’ requested
std::function<int()> accepts a function which takes in no arguments and returns an int. Your proposed lambda takes in an int and returns an int.
Consider std::function<int(int)> instead:
#include <iostream>
#include <functional>
std::function<int(int)> funcGen(int param) {
std::function<int(int)> myGeneratedFunc =
[param](int input) -> int {
return input+param;
};
return myGeneratedFunc;
}
int main() {
std::function<int(int)> myFunc = funcGen(3);
std::cout << "this should be 4=3+1: " << myFunc(1) << "\n";
return 0;
}
I want to store a callback to a std::function<int(int,int>> object. When I use lambda, it works fine. But when I use std::bind to a member function, it compiled error.
There is the sample error code.
#include <functional>
#include <iostream>
using namespace std;
class A
{
public:
void foo()
{
std::function<int(int,int)> callback = std::bind(&A::calc, this);
// std::function<int(int,int)> callback = [this](int a, int b) { return this->calc(a, b); }; // lambda works fine
int r = callback(3, 4);
cout << r << endl;
}
int calc(int b, int c) { return b + c; }
};
int main()
{
A a;
a.foo();
return 0;
}
error message:
In member function 'void A::foo()':
12:72: error: conversion from 'std::_Bind_helper<false, int (A::*)(int, int), A*>::type {aka std::_Bind<std::_Mem_fn<int (A::*)(int, int)>(A*)>}' to non-scalar type 'std::function<int(int, int)>' requested
code link: http://cpp.sh/9pm3c
You need to indicate that A::calc takes 2 parameters, use std::placeholders::X to do it:
std::function<int(int,int)> callback = std::bind(&A::calc, this, std::placeholders::_1,std::placeholders::_2);
I built an interface taking pointers to functions. Sometimes this calculation depends on state, which I want to encapsulate in a class and pass its method:
#include <iostream>
class Printer {
public:
static void print(int i) { // Want to get rid of the static
std::cout << i << "\n";
}
};
template<typename int_func>
void with_1(int_func func) {
func(1);
}
int main(int argc, char const *argv[]) {
Printer printer;
with_1(printer.print);
return 0;
}
I need non-static methods (and would even prefer overloading operator()). However removing the static results in error: a pointer to a bound function may only be used to call the function.
I could use a dummy like this:
Printer printer;
void dummy(int i) {
printer.print(i);
}
int main(int argc, char const *argv[]) {
with_1(dummy);
return 0;
}
But that does not look elegant to me. Can I write a template that accepts both, function pointers and non-static methods? Or is there even a better design pattern for my problem?
You can not simply pass non-static method like this, because they work on instance. A simply solution is to use lambda:
#include <iostream>
class Printer {
public:
static void print(int i) { // Want to get rid of the static
std::cout << i << "\n";
}
};
template<typename int_func>
void with_1(int_func func) {
func(1);
}
int main(int argc, char const *argv[]) {
Printer printer;
// Can use capture by reference because we are sure printer still
// exist during execution of with_1
with_1([&printer](int i){ printer.print(i); });
return 0;
}
example
Try this:
int main(int argc, char const *argv[]) {
Printer printer;
with_1( std::bind( &Printer::print, printer, std::placeholders::_1 ) );
return 0;
}
(You'll need to #include <functional>.)
I can easily bind member functions to a std::function by wrapping them with a lambda expression with capture clause.
class Class
{
Class()
{
Register([=](int n){ Function(n); });
}
void Register(std::function<void(int)> Callback)
{
}
void Function(int Number)
{
}
};
But I want to bind them directly, something like the following.
// ...
Register(&Class::Function);
// ...
I think according to the C++11 standard, this should be supported. However, in Visual Studio 11 I get these compiler errors.
error C2440: 'newline' : cannot convert from 'int' to 'Class *'
error C2647: '.*' : cannot dereference a 'void (__thiscall Class::* )(int)' on a 'int'
I think according to the C++11 standard, this should be supported
Not really, because a non-static member function has an implicit first parameter of type (cv-qualified) YourType*, so in this case it does not match void(int). Hence the need for std::bind:
Register(std::bind(&Class::Function, PointerToSomeInstanceOfClass, _1));
For example
Class c;
using namespace std::placeholders; // for _1, _2 etc.
c.Register(std::bind(&Class::Function, &c, _1));
Edit You mention that this is to be called with the same Class instance. In that case, you can use a simple non-member function:
void foo(int n)
{
theClassInstance.Function(n);
}
then
Class c;
c.Register(foo);
According to Stephan T. Lavavej - "Avoid using bind(), ..., use lambdas".
https://www.youtube.com/watch?v=zt7ThwVfap0&t=32m20s
In this case:
Class()
{
Register([this](int n){ Function(n); });
}
You can use std::bind:
using namespace std::placeholders; // For _1 in the bind call
// ...
Register(std::bind(&Class::Function, this, _1));
In C++ 17, you can use:
Register([=](auto && ...args){ return Function(args...); });
which is sweet especially if the argument list is longer long.
Of course the member function's argument list must then be compatible with the std::function's ones.
With std::function and std::bind, you can treat different class member function the same.
#include <iostream>
#include <functional>
#include <vector>
using namespace std;
using namespace std::placeholders;
class Foo
{
public:
void foo(const string &msg)
{
cout << msg << '\n';
}
};
class Bar
{
public:
void bar(const string &msg, const string &suffix)
{
cout << msg << suffix << '\n';
}
};
int main(int argc, char **argv)
{
Foo foo;
Bar bar;
vector<function<void (const string &msg)>> collection;
collection.push_back(bind(&Foo::foo, &foo, _1));
collection.push_back(bind(&Bar::bar, &bar, _1, "bar"));
for (auto f : collection) {
f("foo");
}
return 0;
}