Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit conversions with std::function [duplicate]

Possible Duplicates:
Why can't my C++ compiler deduce template argument for boost function?
Isn't the template argument (the signature) of std::function part of its type?

I have the following:

#include <functional>

void Foo( std::function<void()>    );
void Foo( std::function<void(int)> );
void Bar();

int main()
{
  Foo( Bar );     // Error: ambiguous
  Foo( [](){} );  // Error: ambiguous

  Foo( std::function<void()>( Bar    ) ); // Ok
  Foo( std::function<void()>( [](){} ) ); // Ok
}

Can I make the first two lines in main() work without the function-style cast in the last two lines? Perhaps with a std::enable_if solution?

like image 672
metal Avatar asked May 31 '11 21:05

metal


2 Answers

Any call to Foo with a parameter which is not exactly one of std::function<void()> and std::function<void(int)> will result in an unresolved overloading. Even silly things like Foo(1) or Foo("abc"). This is because constructors of std::function are templated and accept any type. std::function<void()>(1) would fail at instantiation, but overload resolution happens before instantiation.

So no, you need to provide an exact match to one of the functions, one way or another. You may introduce other overloaded instances of Foo, like

void Foo(void (*)());
void Foo(void (*)(int));

and this will result in a better match and the ambiguity will be no more.

like image 67
n. 1.8e9-where's-my-share m. Avatar answered Oct 12 '22 02:10

n. 1.8e9-where's-my-share m.


It is possible to use SFINAE to make this work correctly, in C++0x. However, MSVC's SFINAE bugs make it impossible for them, as far as I know, and GCC's library implementers don't seem to have noticed, so this unfortunately doesn't work.

You could also try some sort of make_function, I guess. Excuse my variadic templates, it's been a while.

template<typename T> struct function_proxy {
    T f;
    template<typename Ret, typename... T> operator std::enable_if<std::is_same<Ret, decltype(f(std::declval<T>()...))>::value, std::function<Ret(T...)>>::type () {
        return std::function<Ret(T...)>(f);
    }
};
template<typename T> function_proxy<T> make_function(T&& t) {
    return function_proxy { std::forward<T>(t); }
}
like image 31
Puppy Avatar answered Oct 12 '22 01:10

Puppy