Make callback accept temporary on VS 2010 - c++

I have a callback implementation using rvalue references to store arguments that works fine with gcc, but fails to compile in VS 2010 on some code. A short version:
#include <iostream>
#include <string>
class B {
public:
virtual void execute() = 0;
};
template<typename FuncType, typename ArgType>
class F : public B {
public:
F(FuncType func, ArgType && arg) : f(func), arg(arg) {}
void execute() { f(arg); }
private:
FuncType f;
ArgType && arg;
};
template<typename FuncType, typename ArgType>
B * registerFunc(FuncType func, ArgType && arg)
{
return new F<FuncType, ArgType>(func, arg);
}
void myFunction(std::string text)
{
std::cout << "Function " << text << " here" << std::endl;
}
int main()
{
const char text1[] = "sample1";
std::string text2("sample2");
B * b = registerFunc(myFunction, text1);
b->execute();
delete b;
b = registerFunc(myFunction, text2);
b->execute();
delete b;
// VS 2010 fails because of this call
b = registerFunc(myFunction, text2.c_str());
b->execute();
delete b;
return 0;
}
With gcc 4.4 this produces:
$ g++ clbck.cpp -std=c++0x -o clbck && ./clbck
Function sample1 here
Function sample2 here
Function sample2 here
However it fails to compile in VS 2010 when trying to instantiate registerFunc because of the marked line:
error C2664: 'F::F(FuncType,ArgType &&)' : cannot convert parameter 2 from 'const char *' to 'const char *&&'
with
[
FuncType=void (__cdecl *)(std::string),
ArgType=const char *
]
You cannot bind an lvalue to an rvalue reference
Googling discovered a similar error with Boost 1.44 on VS2010, but the recommended solution there is not to use rvalue references at all. Is there really no other way?
And while you're at it, is there something wrong with the way I'm handling these callbacks? It works fine with function pointers and functors (I have yet to test lambdas), the only downside I found is the one described above. (Bear in mind the code shown here is just a small demonstration, in the actual code I don't give user any pointers; I'm actually using this to execute functions in different threads in a Qt application).

I believe that Visual Studio is right to complain, and you can find an explanation here.
In registerFunc, the expression arg is an lvalue (it has a name). If you want to forward it as an rvalue reference, you have to use std::forward :
template<typename FuncType, typename ArgType>
B * registerFunc(FuncType func, ArgType && arg)
{
return new F<FuncType, ArgType>(func, std::forward<ArgType>(arg));
}
The same issue occurs in FuncType constructor, but adding an std::forward there yields an interesting warning :
reference member is initialized to a temporary that doesn't persist after the constructor exits
Unfortunately, I don't enough of rvalue references to help you further, but I doubt that an rvalue reference member makes any sense : rvalue references bind to objects that are about to die, would it make any sense to store that ?

It's not exactly clear what you hope to achieve with respect to the rvalue reference member. It just doesn't look right. You should avoid storing a reference. You can still use things like std::ref and std::cref if you want the function object to store a reference-like object (much like std::bind behaves).
The issue you ran into is that it's not allowed to initialize an rvalue reference with an lvalue of the target type. But you try to do this because the constructor's parameter "arg" is a named rvalue reference which makes it an lvalue expression in the initializer list. You probably used an old GCC version to compile this code. Newer versions will also complain about this.
You can save yourself some trouble by relying on std::bind:
template<class FuncType>
class F : public B {
public:
explicit F(FuncType func)
: f(std::forward<FuncType>(func))
{}
void execute() { f(); }
private:
FuncType f;
};
....
auto fun = std::bind(myFunction,text2.c_str());
B* ptr = new F<decltype(fun)>(fun);
If you really want to deal with the parameter binding yourself, you should do it like this:
template<class FuncType, class ParamType>
class F : public B {
public:
F(FuncType func, ParamType para)
: f(std::forward<FuncType>(func))
, p(std::forward<ParamType>(para))
void execute() { f(p); }
private:
FuncType f;
ParamType p;
};
Keep in mind that the parameter type T&& where T can be deduced has a special meaning. It's a "catch-all" parameter. Template argument deduction will make T an lvalue reference (and T&& as well by the reference collapsing rules) in case the argument was an lvalue. So, if you always want the parameter to be stored as a copy you have to write
template<class FuncType, class ArgType>
B * registerFunc(FuncType func, ArgType && arg)
{
typedef typename std::decay<ArgType>::type datype;
return new F<FuncType,datype>(func, std::forward<ArgType>(arg));
}
I would prefer a registerFunc function like this. It copies the function object and parameter object by default. Overriding this can be done via std::ref and std::cref:
registerFunc(some_func,std::cref(some_obj));

Why not just use lambda expressions?
class B {
virtual void execute() = 0;
};
template<typename T> class F : public B {
T t;
public:
F(T&& arg) : t(std::forward<T>(arg)) {}
void execute() { return t(); }
};
template<typename T> F<T> make_f(T&& t) {
return F<T>(std::forward<T>(t));
}
int main() {
std::string var;
B* callback = make_f([=]() {
std::cout << var << std::endl;
});
}
Or, indeed, std::function<void()>, which is what it's for.

Related

Problems using std::unique_ptr with std::bind [duplicate]

I wonder how the following can be done
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, s)(); // Error.
bind(f, move(s))(); // Error.
bind(f, ref(s))(); // Error.
}
How can I pass an rvalue reference and store it as an rvalue reference (possibly wrapped) in the call wrapper? I know I can manually write up a class like std::reference_wrapper<> that has a conversion function to T&&, but I would rather want to avoid that and use Standard technology.
I implemented it like AProgrammer recommends:
template<typename T> struct adv {
T t;
explicit adv(T &&t):t(forward<T>(t)) {}
template<typename ...U> T &&operator()(U &&...) {
return forward<T>(t);
}
};
template<typename T> adv<T> make_adv(T &&t) {
return adv<T>{forward<T>(t)};
}
namespace std {
template<typename T>
struct is_bind_expression< adv<T> > : std::true_type {};
}
Now I can say
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, make_adv(move(s)))(); // Works!
}
If we pass an lvalue to make_adv, it will forward it as an lvalue referring to the input argument, so it can be used as a replacement for std::ref, in this case.
My take on this.
20.8.10.1.2/10 in N3225
The values of the bound arguments v1, v2, ..., vN and their corresponding types V1, V2, ..., VN
depend on the types TiD derived from the call to bind and the cv-qualifiers cv of the call wrapper g as
follows:
if TiD is reference_wrapper, the argument is tid.get() and its type Vi is T&;
if the value of is_bind_expression::value is true, the argument is tid(std::forward(uj)...)
and its type Vi is result_of::type;
if the value j of is_placeholder::value is not zero, the argument is std::forward(uj)
and its type Vi is Uj&&;
otherwise, the value is tid and its type Vi is TiD cv &.
So the only possibility to have a rvalue reference is to have is_bind_expression<TiD>::value true or is_placeholder<TiD>::value not zero. The second possibility has implications you don't want and achieving the wanted result with the first would imply that the problem we are trying to solve is solved if we restrict to the standard provided types. So, the only possibility would be to provide your own wrapper and a specialisation for is_bind_expression<TiD> (that is allowed by 20.8.10.1.1/1) as I don't see one.
How can I pass an rvalue reference and store it as an rvalue reference in the call wrapper?
The problem here is that such a bind function object can be invoked multiple times. If the function object forwarded a bound parameter as rvalue this would obviously only work once. So, this is a bit of a safety issue.
But in some cases this kind of forwarding is exactly what you want. You could use a lambda as an intermediary:
bind([](string& s){f(move(s));},move(s));
Basically, I came up with this bind+lambda combination as a workaround for a missing "move-capture".
I was googling for "reference_wrapper for rvalues" when I stumbled on this question.
Not sure whether my answer would be useful, it is not related to std::bind and actually doesn't work with it, but for some other use cases it might help somebody.
Here's my attempt to implement rvalue_reference_wrapper:
#pragma once
#include <type_traits>
#include <memory>
#include <utility>
template<class T>
class rvalue_reference_wrapper
{
public:
static_assert(::std::is_object<T>::value, "rvalue_reference_wrapper<T> requires T to be an object type.");
using type = T;
rvalue_reference_wrapper(T& ref_value) = delete;
rvalue_reference_wrapper(T&& ref_value) noexcept
: _pointer(::std::addressof(ref_value))
{
}
operator T&&() && noexcept
{
return ::std::move(*_pointer);
}
T&& get() && noexcept
{
return ::std::move(*_pointer);
}
template<class... ArgTypes>
auto operator()(ArgTypes&&... args) &&
-> decltype(::std::invoke(::std::declval<rvalue_reference_wrapper<T>>().get(), ::std::forward<ArgTypes>(args)...))
{
return (::std::invoke(::std::move(*this).get(), ::std::forward<ArgTypes>(args)...));
}
private:
T* _pointer;
};
template<class T>
inline rvalue_reference_wrapper<T> rv_ref(T& ref_value) = delete;
template<class T>
inline ::std::enable_if_t<!(::std::is_lvalue_reference<T>::value), rvalue_reference_wrapper<T>> rv_ref(T&& ref_value) noexcept
{
return rvalue_reference_wrapper<T>(::std::forward<T>(ref_value));
}
#ifdef _MSC_VER
namespace std
{
template<class T>
struct _Unrefwrap_helper<rvalue_reference_wrapper<T>>
{
using type = T &&;
static constexpr bool _Is_refwrap = true;
};
}
#else
#pragma error("TODO : implement...")
#endif
The last specialization in namespace std allows MSVC's implementation of standard library to work with my type, e.g. when using std::make_tuple:
int a = 42;
auto p_int = std::make_unique<int>(42);
auto test_tuple = std::make_tuple(42, std::ref(a), rv_ref(std::move(p_int)));
static_assert(std::is_same<decltype(test_tuple), std::tuple<int, int &, std::unique_ptr<int>&&>>::value, "unexpected result");
I believe it would not be hard to implement similar "unwrapping" logic for other standard library implementations.
You can use a mutable lambda object.
auto func = [=]() mutable {
f(std::move(s));
};

How does wrapping a function pointer and function object work in generic code?

The following template definition
template <typename Func, typename ReturnType, typename... Arguments>
class Command
{
public:
Command(Func f) : m_func(f) { }
ReturnType operator()(Arguments... funcArgs) { return m_func(funcArgs...); }
private:
Func m_func;
};
gives an error message with gcc 4.7.3 (error: field 'Command::m_func' invalidly declared function type) when instantiated with the following test code:
void testFunction(int i, double d)
{
std::cout << "TestFunctor::operator()(" << i << ", " << d << ") called." << std::endl;
}
int main()
{
void (&fRef)(int, double) = TestFunction;
Command<void(int, double), void, int, double> testCommand(fRef);
}
The error message also occurs if I pass TestFunction without the address-of operator into the testCommand constructor, but disappears if I pass either an explicitly named function pointer or use the address-of operator to pass the parameter. I'm under the impression that this code should work given Chapter 5 of Modern C++ Design.
What is the reasoning behind not being able to store a reference to a function, but function pointers work fine? Are there any workarounds that would allow this to compile without losing support for being able to pass functors as arguments to Command's constructor as well?
Changing one line could fix it:
Command<void(*)(int, double), void, int, double> testCommand(fRef);
The difference is, you're passing a function pointer now, instead of a function type. (Functions aren't copyable, but pointers are).
The reference fRef decays to a function pointer when you pass it.
I wouldn't suggest using std::function if performance mattered.
See it live on Coliru
Note that with a little rewriting, you can make it all work much nicer:
int main()
{
auto command = make_command(testFunction);
command(1, 3.14);
}
To do this, I'd suggest changing the Command template to be:
template <typename Func>
class Command
{
Func m_func;
public:
Command(Func f) : m_func(f) { }
template <typename... A> auto operator()(A... args) const
-> decltype(m_func(args...))
{ return m_func(args...); }
};
And now you can have type-deduction on the Func template parameter by having a factory function:
template <typename Func> Command<Func> make_command(Func f)
{
return Command<Func>(f);
}
See this approach live on Coliru too. Of course, the output it the same:
TestFunctor::operator()(1, 3.14) called.
C++11 offers an std::function template. You don't have to mess with function pointers.
You can pass those by reference, copy them, move them and they can even be used to store lambdas:
std::function<void()> func = []() { std::cout << "Hi" << std::endl; };

Is there a reference_wrapper<> for rvalue references?

I wonder how the following can be done
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, s)(); // Error.
bind(f, move(s))(); // Error.
bind(f, ref(s))(); // Error.
}
How can I pass an rvalue reference and store it as an rvalue reference (possibly wrapped) in the call wrapper? I know I can manually write up a class like std::reference_wrapper<> that has a conversion function to T&&, but I would rather want to avoid that and use Standard technology.
I implemented it like AProgrammer recommends:
template<typename T> struct adv {
T t;
explicit adv(T &&t):t(forward<T>(t)) {}
template<typename ...U> T &&operator()(U &&...) {
return forward<T>(t);
}
};
template<typename T> adv<T> make_adv(T &&t) {
return adv<T>{forward<T>(t)};
}
namespace std {
template<typename T>
struct is_bind_expression< adv<T> > : std::true_type {};
}
Now I can say
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, make_adv(move(s)))(); // Works!
}
If we pass an lvalue to make_adv, it will forward it as an lvalue referring to the input argument, so it can be used as a replacement for std::ref, in this case.
My take on this.
20.8.10.1.2/10 in N3225
The values of the bound arguments v1, v2, ..., vN and their corresponding types V1, V2, ..., VN
depend on the types TiD derived from the call to bind and the cv-qualifiers cv of the call wrapper g as
follows:
if TiD is reference_wrapper, the argument is tid.get() and its type Vi is T&;
if the value of is_bind_expression::value is true, the argument is tid(std::forward(uj)...)
and its type Vi is result_of::type;
if the value j of is_placeholder::value is not zero, the argument is std::forward(uj)
and its type Vi is Uj&&;
otherwise, the value is tid and its type Vi is TiD cv &.
So the only possibility to have a rvalue reference is to have is_bind_expression<TiD>::value true or is_placeholder<TiD>::value not zero. The second possibility has implications you don't want and achieving the wanted result with the first would imply that the problem we are trying to solve is solved if we restrict to the standard provided types. So, the only possibility would be to provide your own wrapper and a specialisation for is_bind_expression<TiD> (that is allowed by 20.8.10.1.1/1) as I don't see one.
How can I pass an rvalue reference and store it as an rvalue reference in the call wrapper?
The problem here is that such a bind function object can be invoked multiple times. If the function object forwarded a bound parameter as rvalue this would obviously only work once. So, this is a bit of a safety issue.
But in some cases this kind of forwarding is exactly what you want. You could use a lambda as an intermediary:
bind([](string& s){f(move(s));},move(s));
Basically, I came up with this bind+lambda combination as a workaround for a missing "move-capture".
I was googling for "reference_wrapper for rvalues" when I stumbled on this question.
Not sure whether my answer would be useful, it is not related to std::bind and actually doesn't work with it, but for some other use cases it might help somebody.
Here's my attempt to implement rvalue_reference_wrapper:
#pragma once
#include <type_traits>
#include <memory>
#include <utility>
template<class T>
class rvalue_reference_wrapper
{
public:
static_assert(::std::is_object<T>::value, "rvalue_reference_wrapper<T> requires T to be an object type.");
using type = T;
rvalue_reference_wrapper(T& ref_value) = delete;
rvalue_reference_wrapper(T&& ref_value) noexcept
: _pointer(::std::addressof(ref_value))
{
}
operator T&&() && noexcept
{
return ::std::move(*_pointer);
}
T&& get() && noexcept
{
return ::std::move(*_pointer);
}
template<class... ArgTypes>
auto operator()(ArgTypes&&... args) &&
-> decltype(::std::invoke(::std::declval<rvalue_reference_wrapper<T>>().get(), ::std::forward<ArgTypes>(args)...))
{
return (::std::invoke(::std::move(*this).get(), ::std::forward<ArgTypes>(args)...));
}
private:
T* _pointer;
};
template<class T>
inline rvalue_reference_wrapper<T> rv_ref(T& ref_value) = delete;
template<class T>
inline ::std::enable_if_t<!(::std::is_lvalue_reference<T>::value), rvalue_reference_wrapper<T>> rv_ref(T&& ref_value) noexcept
{
return rvalue_reference_wrapper<T>(::std::forward<T>(ref_value));
}
#ifdef _MSC_VER
namespace std
{
template<class T>
struct _Unrefwrap_helper<rvalue_reference_wrapper<T>>
{
using type = T &&;
static constexpr bool _Is_refwrap = true;
};
}
#else
#pragma error("TODO : implement...")
#endif
The last specialization in namespace std allows MSVC's implementation of standard library to work with my type, e.g. when using std::make_tuple:
int a = 42;
auto p_int = std::make_unique<int>(42);
auto test_tuple = std::make_tuple(42, std::ref(a), rv_ref(std::move(p_int)));
static_assert(std::is_same<decltype(test_tuple), std::tuple<int, int &, std::unique_ptr<int>&&>>::value, "unexpected result");
I believe it would not be hard to implement similar "unwrapping" logic for other standard library implementations.
You can use a mutable lambda object.
auto func = [=]() mutable {
f(std::move(s));
};

On reference_wrapper and callable objects

Given the following callable object:
struct callable : public std::unary_function <void, void>
{
void
operator()() const
{
std::cout << "hello world" << std::endl;
}
};
a std::tr1::reference_wrapper<> calls through it:
callable obj;
std::tr1::ref(obj)();
Instead, when the operator() accepts an argument:
struct callable : public std::unary_function <int, void>
{
void
operator()(int n) const
{
std::cout << n << std::endl;
}
};
std::tr1::bind accepts a reference_wrapper to it as a callable wrapper...
callable obj;
std::tr1::bind( std::tr1::ref(obj), 42 )();
but what's wrong with this?
std::tr1::ref(obj)(42);
g++-4.4 fails to compile with the following error:
test.cpp:17: error: no match for call to ‘(std::tr1::reference_wrapper<const callable>) (int)’
/usr/include/c++/4.4/tr1_impl/functional:462: note: candidates are: typename std::tr1::result_of<typename std::tr1::_Function_to_function_pointer<_Tp, std::tr1::is_function::value>::type(_Args ...)>::type std::tr1::reference_wrapper<_Tp>::operator()(_Args& ...) const [with _Args = int, _Tp = const callable]
The implementation of tr1 reference_wrapper of g++-4.4 is equipped with the following operator:
template<typename... _Args>
typename result_of<_M_func_type(_Args...)>::type
operator()(_Args&... __args) const
{
return __invoke(get(), __args...);
}
It takes arguments by reference. Hence the reference_wrapper cannot be invoked passing an r-value argument:
std::tr1::ref(obj)(42);
instead:
int arg = 42;
std::tr1::ref(obj)(arg);
works just fine.
std::tr1::bind( std::tr1::ref(obj), 42 )()
works because bind takes the arguments by copy.
What makes you sure there's anything wrong with it? I believe this should work:
#include <functional>
#include <iostream>
struct callable : public std::unary_function <int, void>
{
void
operator()(int n) const
{
std::cout << n << std::endl;
}
};
int main() {
callable obj;
std::tr1::ref(obj)(42);
return 0;
}
At least with MS VC++ 9, it compiles and executes just fine, and offhand I can't see any reason it shouldn't work with other compilers as well.
Edit: Doing some looking at TR1, I take that back. It works with VC++ 9, but I don't think it's really required to work. VC++ 9 doesn't support variable template arguments, so they're supporting this via overloading. Rather deeply buried (<functional> includes <xawrap>, which includes <xawrap0> [which, in turn, includes <xawrap1>]) is code to generate reference and (importantly) reference to const variants for up to 10 arguments. It's almost certainly the inclusion of the reference to const variants that allows this to work.
First of all, the use of std::unary_function for a null-ary function looks odd. "unary" = takes one argument. I'm not sure whether it's okay to use ArgType=void.
Secondly, you have it backwards. The first template parameter is about the argument type and the second one is about the return type. So, your unary function object should be defined like this:
struct callable : public std::unary_function<int,void>
{
void operator()(int n) const
{
std::cout << n << std::endl;
}
};

Nested bind expressions

This is a followup question to my previous question.
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&& c) { return c();}
template <class C> void func_wrapper(C&& c) { func( std::bind(doit<C>, std::forward<C>(c)) ); }
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
I'm getting a compile errors deep in the C++ headers:
functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
functional:1137: error: conversion from ‘int’ to non-scalar type ‘std::_Bind<std::_Mem_fn<int (bar::*)(int)>(bar, int)>’ requested
func_wrapper(foo) is supposed to execute func(doit(foo)). In the real code it packages the function for a thread to execute. func would the function executed by the other thread, doit sits in between to check for unhandled exceptions and to clean up. But the additional bind in func_wrapper messes things up...
At the beginning, please let me introduce 2 key points:
a: When using nested std::bind, the inner std::bind is evaluated first, and the return value will be substituted in its place while the outer std::bind is evaluated. That means std::bind(f, std::bind(g, _1))(x) executes as same as f(g(x)) does. The inner std::bind is supposed to be wrapped by std::ref if the outer std::bind wants a functor rather than a return value.
b: The r-value reference cannot be correctly forwarded to the function by using std::bind. And the reason has already been illustrated in detail.
So, let's look at the question. The most importance function here might be func_wrapper which is intended to perform 3 purposes:
Perfect forwarding a functor to doit function template at first,
then using std::bind to make doit as a closure,
and letting func function template execute the functor returned by std::bind at last.
According to point b, purpose 1 cannot be fulfilled. So, let's forget perfect forwarding and doit function template has to accept a l-value reference parameter.
According to point a, purpose 2 will be performed by using std::ref.
As a result, the final version might be:
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&/*&*/ c) // r-value reference can't be forwarded via std::bind
{
return c();
}
template <class C> void func_wrapper(C&& c)
{
func(std::bind(doit<C>,
/* std::forward<C>(c) */ // forget pefect forwarding while using std::bind
std::ref(c)) // try to pass the functor itsself instead of its return value
);
}
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error disappears
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error disappears
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
But, if you really want to achieve purpose 1 and 2, how? Try this:
#include <functional>
#include <iostream>
void foo()
{
}
struct bar {
void operator()() {}
void dosomething() {}
};
static bar b;
template <typename Executor>
void run(Executor&& e)
{
std::cout << "r-value reference forwarded\n";
e();
}
template <typename Executor>
void run(Executor& e)
{
std::cout << "l-value reference forwarded\n";
e();
}
template <typename Executor>
auto func(Executor&& e) -> decltype(e())
{
return e();
}
template <bool b>
struct dispatcher_traits {
enum { value = b };
};
template <typename Executor, bool is_lvalue_reference>
class dispatcher {
private:
static void dispatch(Executor& e, dispatcher_traits<true>)
{
run(e);
}
static void dispatch(Executor& e, dispatcher_traits<false>)
{
run(std::ref(e));
}
public:
static void forward(Executor& e)
{
dispatch(e, dispatcher_traits<is_lvalue_reference>());
}
};
template <typename Executor>
void func_wrapper(Executor&& e)
{
typedef dispatcher<Executor,
std::is_lvalue_reference<Executor>::value>
dispatcher_type;
func(std::bind(&dispatcher_type::forward, std::ref(e)));
}
int main()
{
func_wrapper(foo); // l-value
func_wrapper(b); // l-value
func_wrapper(bar()); // r-value
func_wrapper(std::bind(&bar::dosomething, &b)); // r-value
func_wrapper([](){}); // r-value
}
Let me explain some points:
To reduce lots of return statements, changing functor signature from int() to void().
The 2 run() function templates are used to check whether the original functor parameter is perfect forwarded or not.
dispatcher_traits is going to map bool constant to type.
You'd better name dispatcher::forward to differ from dispatcher::dispatch or you have to invoke std::bind template with dispatcher::forward's signature.
Looking at this the second time now, and I think I have a plausable explanation for the first error you are seeing.
In this case, it's more helpful to look at the complete error and the template instantiations that lead up to it. The error printed by my compiler (GCC 4.4), for example, ends with the following lines:
test.cpp:12: instantiated from ‘decltype (c()) func(C&&) [with C = std::_Bind<int (*(int (*)()))(int (&)())>]’
test.cpp:16: instantiated from ‘void func_wrapper(C&&) [with C = int (&)()]’
test.cpp:22: instantiated from here
/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
Now looking at this bottom-up, the actual error message seems correct; the types the compiler has deduced are incompatible.
The first template instantiation, at func_wrapper, clearly shows what type the compiler has deduced from the actual parameter foo in func_wrapper(foo). I personally expected this to be a function pointer, but it is in fact a function reference.
The second template instantiation is hardly readable. But messing around with std::bind a bit, I learned that the format of the textual representation GCC prints for a bind functor is roughly:
std::_Bind<RETURN-TYPE (*(BOUND-VALUE-TYPES))(TARGET-PARAMETER-TYPES)>
So tearing it apart:
std::_Bind<int (*(int (*)()))(int (&)())>
// Return type: int
// Bound value types: int (*)()
// Target parameter types: int (&)()
This is where the incompatible types start. Apparently, even though c in func_wrapper is a function reference, it turns into a function pointer once passed to std::bind, resulting in the type incompatibility. For what it's worth, std::forward doesn't matter at all in this case.
My reasoning here is that std::bind only seems to care about values, and not references. In C/C++, there's no such thing as a function value; there's only references and pointers. So when the function reference is dereferenced, the compiler can only meaningfully give you a function pointer.
The only control you have over this is your template parameters. You will have to tell the compiler that you're dealing with a function pointer from the start to make this work. It's probably what you had in mind anyways. To do that, explicitly specify the type you want for the template parameter C:
func_wrapper<int (*)()>(foo);
Or the more brief solution, explicitly take the function's address:
func_wrapper(&foo); // with C = int (*)()
I'll get back to you if I ever figure out the second error. :)