std::function overload ambiguity [duplicate] - c++

Given the following code, what is the reason behind the ambiguity? Can I circumvent it or will I have to keep the (annoying) explicit casts?
#include <functional>
using namespace std;
int a(const function<int ()>& f)
{
return f();
}
int a(const function<int (int)>& f)
{
return f(0);
}
int x() { return 22; }
int y(int) { return 44; }
int main()
{
a(x); // Call is ambiguous.
a(y); // Call is ambiguous.
a((function<int ()>)x); // Works.
a((function<int (int)>)y); // Works.
return 0;
}
Interestingly, if I comment out the a() function with the function<int ()> parameter and call a(x) in my main, the compilation correctly fails because of the type mismatch between x and the argument function<int (int)> of the only a() function available. If the compiler fails in that case, why would there be any ambiguity when the two a() functions are present?
I've tried with VS2010 and g++ v. 4.5. Both give me the exact same ambiguity.

The problem is that both function<int()> and function<int(int)> are constructible from the same function. This is what the constructor declaration of std::function looks like in VS2010:
template<class _Fx>
function(_Fx _Func, typename _Not_integral<!_Is_integral<_Fx>::value, int>::_Type = 0);
Ignoring the SFINAE part, it is constructible from pretty much anything.
std::/boost::function employ a technique called type erasure, to allow arbitary objects/functions to be passed in, so long they satisfy the signature when being called. One drawback from that is, that you get an error in the deepest part of the implementation (where the saved function is being called) when supplying an object which can't be called like the signature wants it to, instead of in the constructor.
The problem can be illustrated with this little class:
template<class Signature>
class myfunc{
public:
template<class Func>
myfunc(Func a_func){
// ...
}
};
Now, when the compiler searches for valid functions for the overload set, it tries to convert the arguments if no perfect fitting function exists. The conversion can happen through the constructor of the parameter of the function, or through a conversion operator of the argument given to the function. In our case, it's the former.
The compiler tries the first overload of a. To make it viable, it needs to make a conversion. To convert a int(*)() to a myfunc<int()>, it tries the constructor of myfunc. Being a template that takes anything, the conversion naturally succeeds.
Now it tries the same with the second overload. The constructor still being the same and still taking anything given to it, the conversion works too.
Being left with 2 functions in the overload set, the compiler is a sad panda and doesn't know what to do, so it simply says the call is ambigious.
So in the end, the Signature part of the template does belong to the type when making declarations/definitions, but doesn't when you want to construct an object.
Edit:
With all my attention on answering the title-question, I totally forgot about your second question. :(
Can I circumvent it or will I have to keep the (annoying) explicit casts?
Afaik, you have 3 options.
Keep the cast
Make a function object of the appropriate type and pass that
function<int()> fx = x;
function<int(int)> fy = y;
a(fx);
a(fy);
Hide the tedious casting in a function and use TMP to get the right signature
The TMP (template metaprogramming) version is quite verbose and with boilerplate code, but it hides the casting from the client. An example version can be found here, which relies on the get_signature metafunction that is partially specialized on function pointer types (and provides a nice example how pattern matching can work in C++):
template<class F>
struct get_signature;
template<class R>
struct get_signature<R(*)()>{
typedef R type();
};
template<class R, class A1>
struct get_signature<R(*)(A1)>{
typedef R type(A1);
};
Of course, this needs to be extended for the number of arguments you want to support, but that is done once and then buried in a "get_signature.h" header. :)
Another option I consider but immediatly discarded was SFINAE, which would introduce even more boilerplate code than the TMP version.
So, yeah, that are the options that I know of. Hope one of them works for you. :)

I've seen this question come up one too many times. libc++ now compiles this code without ambiguity (as a conforming extension).
Overdue Update
This "extension" proved sufficiently popular that it was standardized in C++14 (though I was not personally responsible for getting that job done).
In hindsight, I did not get this extension exactly correct. Earlier this month (2015-05-09) the committee voted in LWG issue 2420 which effectively changes the definition of Callable so that if the std::function has a void return type it will ignore the return type of the wrapped functor, but still otherwise consider it Callable if everything else matches up, instead of considering it not Callable.
This post-C++14 tweak does not impact this particular example since the return types involved are consistently int.

Here's an example of how to wrap std::function in a class that checks invokability of its constructor parameters:
template<typename> struct check_function;
template<typename R, typename... Args>
struct check_function<R(Args...)>: public std::function<R(Args...)> {
template<typename T,
class = typename std::enable_if<
std::is_same<R, void>::value
|| std::is_convertible<
decltype(std::declval<T>()(std::declval<Args>()...)),
R>::value>::type>
check_function(T &&t): std::function<R(Args...)>(std::forward<T>(t)) { }
};
Use like this:
int a(check_function<int ()> f) { return f(); }
int a(check_function<int (int)> f) { return f(0); }
int x() { return 22; }
int y(int) { return 44; }
int main() {
a(x);
a(y);
}
Note that this isn't quite the same as overloading on function signature, as it treats convertible argument (and return) types as equivalent. For exact overloading, this should work:
template<typename> struct check_function_exact;
template<typename R, typename... Args>
struct check_function_exact<R(Args...)>: public std::function<R(Args...)> {
template<typename T,
class = typename std::enable_if<
std::is_convertible<T, R(*)(Args...)>::value>::type>
check_function_exact(T &&t): std::function<R(Args...)>(std::forward<T>(t)) { }
};

std::function<T> has a conversion ctor that takes an arbitrary type (i.e., something other than a T). Sure, in this case, that ctor would result in a type mismatch error, but the compiler doesn't get that far -- the call is ambiguous simply because the ctor exists.

Related

Is there any way to detect overloaded member function by name alone? (not to detect name)

I am wishful here, but I want to be precise about the question. I want to improve implementation of detecting member templates by their names alone, but I came across an obstacle. I can't find any way to detect overloaded static/non-static member functions. Very important part of this question is, that I can't use this trick, because it detects any name (I'm already using it in current implementation, kinda useful), and I can't specify the types, because that misses the point of using names alone.
For reference, see my other question. I posted current has_member_template_bar implementation as an answer there. I don't think I should post all of it in this question.
The question stays the same - Can we detect overloaded member functions, without specifying their arguments, or using mentioned trick? I know I'm maybe asking for impossible, but it never hurts to ask.
The question stays the same - Can we detect overloaded member functions, without specifying their arguments, or using mentioned trick? I know I'm maybe asking for impossible, but it never hurts to ask
Actually, it is not impossible.
It follows a minimal, working example:
template<typename T, typename R, typename... A>
void proto(R(T::*)(A...));
template<typename, typename = void>
constexpr bool has_single_f = false;
template<typename T>
constexpr bool has_single_f<T, decltype(proto(&T::f))> = true;
struct S {
void f(int) {}
void f(char) {}
};
struct U {
void f() {}
};
int main() {
static_assert(not has_single_f<S>, "!");
static_assert(has_single_f<U>, "!");
}
Of course, you need to add more stuff to distinguish between member methods and data members, but it's trivial to add them (see the header type_traits) and I tried to keep the example as minimal as possible.
The basic idea is that the call to proto fails if the given function is overloaded, for it's an ambiguous call.
Anyway, the error is discarded because of SFINAE rules.
Arguments are not required to be specified as requested.
Note also that proto does not require to be defined, but it's important that its return type is void. Otherwise you have to slightly modify the call to decltype as it follows:
template<typename T>
constexpr bool has_single_f<T, decltype(proto(&T::f), void())> = true;
As you can see from the example code, the static_asserts verify that f is overloaded in S and it is not in U.
The example above is based on template variables, that are part of the language since C++14.
If you prefer the well known struct based solution that works with C++11, you can use the following detector:
#include<type_traits>
//...
template<typename, typename = void>
struct has_single_f: std::false_type {};
template<typename T>
struct has_single_f<T, decltype(proto(&T::f))>: std::true_type {};
//...
int main() {
static_assert(not has_single_f<S>::value, "!");
static_assert(has_single_f<U>::value, "!");
}

Selective forwarding function

The task is to create a single-argument function that forwards all types apart from one (Foo), which it converts (to Bar).
(Let us assume there exists a conversion from Foo to Bar).
Here is the usage scenario:
template<typename Args...>
void f( Args... args )
{
g( process<Args>(args)... );
}
(I've tried to extract/simplify it from the original context here. -- if I've made a mistake, please someone tell me!)
Here are two possible implementations:
template<typename T>
T&& process(T&& t) {
return std::forward<T>(t);
}
Bar process(Foo x) {
return Bar{x};
}
And...
template <typename T, typename U>
T&& process(U&& u) {
return std::forward<T>(std::forward<U>(u));
}
template <typename T>
Bar process(Foo x) {
return Bar{x};
}
I have it on good authority (here) that the second one is preferable.
However, I can't understand the given explanation. I think this is delving into some of the darkest corners of C++.
I think I'm missing machinery necessary to understand what's going on. Could someone explain in detail? If it is too much digging, could anyone recommend a resource for learning the necessary prerequisite concepts?
EDIT: I would like to add that in my particular case the function signature is going to match one of the typedef-s on this page. That is to say, every argument is going to be either PyObject* (with PyObject being an ordinary C struct) or some basic C type like const char*, int, float. So my guess is that the lightweight implementation may be most appropriate (I'm not a fan of over-generalising). But I am really interested in acquiring the right mindset to solve such problems as these.
I sense a minor misconception in your understanding of the use case you are facing.
First of all, this is a function template:
struct A
{
template <typename... Args>
void f(Args... args)
{
}
};
And this is not a function template:
template <typename... Args>
struct A
{
void f(Args... args)
{
}
};
In the former definition (with a function template) the argument type deduction takes place. In the latter, there is no type deduction.
You aren't using a function template. You're using a non-template member function from a class template, and for this particular member function its signature is fixed.
By defining your trap class like below:
template <typename T, T t>
struct trap;
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R call(Args... args);
};
and referring to its member function like below:
&trap<decltype(&Base::target), &Base::target>::call;
you end up with a pointer to a static non-template call function with a fixed signature, identical to the signature of the target function.
Now, that call function serves as an intermediate invoker. You will be calling the call function, and that function will call the target member function, passing its own arguments to initialize target's parameters, say:
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R call(Args... args)
{
return (get_base()->*t)(args...);
}
};
Suppose the target function used to instantiate the trap class template is defined as follows:
struct Base
{
int target(Noisy& a, Noisy b);
};
By instantiating the trap class you end up with the following call function:
// what the compiler *sees*
static int call(Noisy& a, Noisy b)
{
return get_base()->target(a, b);
}
Luckily, a is passed by reference, it is just forwarded and bound by the same kind of reference in the target's parameter. Unfortunately, this doesn't hold for the b object - no matter if the Noisy class is movable or not, you're making multiple copies of the b instance, since that one is passed by value:
the first one: when the call function is invoked itself from an external context.
the second one: to copy b instance when calling the target function from the body of call.
DEMO 1
This is somewhat inefficient: you could have saved at least one copy-constructor call, turning it into a move-constructor call if only you could turn the b instance into an xvalue:
static int call(Noisy& a, Noisy b)
{
return get_base()->target(a, std::move(b));
// ~~~~~~~~~~~^
}
Now it would call a move constructor instead for the second parameter.
So far so good, but that was done manually (std::move added knowing that it's safe to apply the move semantics). Now, the question is, how could the same functionality be applied when operating on a parameter pack?:
return get_base()->target(std::move(args)...); // WRONG!
You can't apply std::move call to each and every argument within the parameter pack. This would probably cause compiler errors if applied equally to all arguments.
DEMO 2
Fortunately, even though Args... is not a forwarding-reference, the std::forward helper function can be used instead. That is, depending on what the <T> type is in std::forward<T> (an lvalue reference or a non-lvalue-reference) the std::forward will behave differently:
for lvalue references (e.g. if T is Noisy&): the value category of the expression remains an lvalue (i.e. Noisy&).
for non-lvalue-references (e.g. if T is Noisy&& or a plain Noisy): the value category of the expression becomes an xvalue (i.e. Noisy&&).
Having that said, by defining the target function like below:
static R call(Args... args)
{
return (get_base()->*t)(std::forward<Args>(args)...);
}
you end up with:
static int call(Noisy& a, Noisy b)
{
// what the compiler *sees*
return get_base()->target(std::forward<Noisy&>(a), std::forward<Noisy>(b));
}
turning the value category of the expression involving b into an xvalue of b, which is Noisy&&. This lets the compiler pick the move constructor to initialize the second parameter of the target function, leaving a intact.
DEMO 3 (compare the output with DEMO 1)
Basically, this is what the std::forward is for. Usually, std::forward is used with a forwarding-reference, where T holds the type deduced according to the rules of type deduction for forwarding references. Note that it always requires from you to pass over the <T> part explicitly, since it will apply a different behavior depending on that type (not depending on the value category of its argument). Without the explicit type template argument <T>, std::forward would always deduce lvalue references for arguments referred to through their names (like when expanding the parameter pack).
Now, you wanted to additionally convert some of the arguments from one type to another, while forwarding all others. If you don't care about the trick with std::forwarding arguments from the parameter pack, and it's fine to always call a copy-constructor, then your version is OK:
template <typename T> // transparent function
T&& process(T&& t) {
return std::forward<T>(t);
}
Bar process(Foo x) { // overload for specific type of arguments
return Bar{x};
}
//...
get_base()->target(process(args)...);
DEMO 4
However, if you want to avoid the copy of that Noisy argument in the demo, you need to somehow combine std::forward call with the process call, and pass over the Args types, so that std::forward could apply proper behavior (turning into xvalues or not doing anything). I just gave you a simple example of how this could be implemented:
template <typename T, typename U>
T&& process(U&& u) {
return std::forward<T>(std::forward<U>(u));
}
template <typename T>
Bar process(Foo x) {
return Bar{x};
}
//...
get_base()->target(process<Args>(args)...);
But this is just one of the options. It can be simplified, rewritten, or reordered, so that std::forward is called before you call the process function (your version):
get_base()->target(process(std::forward<Args>(args))...);
DEMO 5 (compare the output with DEMO 4)
And it will work fine as well (that is, with your version). So the point is, the additional std::forward is just to optimize your code a little, and the provided idea was just one of the possible implementations of that functionality (as you can see, it brings about the same effect).
Would not be the first part of Version 2 sufficient? only:
template <typename T, typename U>
T&& process(U&& u) {
return std::forward<T>(std::forward<U>(u));
}
Given a usage case with an existing conversion (constructor for "Bar" from "Foo"), like:
struct Foo {
int x;
};
struct Bar {
int y;
Bar(Foo f) {
y = f.x;
}
};
int main() {
auto b = process<Bar>(Foo()); // b will become a "Bar"
auto i = process<int>(1.5f);
}
You are forced to specify the first template parameter (the type to convert to) anyway because the compiler cannot deduce it. So it knows what type you expect and will construct a temporary object of type "Bar" because there is a constructor.

Why does auto return type change the overload resolution?

Thanks to decltype as a return type, C++11 made it extremely easy to introduce decorators. For instance, consider this class:
struct base
{
void fun(unsigned) {}
};
I want to decorate it with additional features, and since I will do that several times with different kinds of decorations, I first introduce a decorator class that simply forwards everything to base. In the real code, this is done via std::shared_ptr so that I can remove decorations and recover the "naked" object, and everything is templated.
#include <utility> // std::forward
struct decorator
{
base b;
template <typename... Args>
auto
fun(Args&&... args)
-> decltype(b.fun(std::forward<Args>(args)...))
{
return b.fun(std::forward<Args>(args)...);
}
};
Perfect forwarding and decltype are just wonderful. In the real code, I actually use a macro that just needs the name of the function, all the rest is boilerplate.
And then, I can introduce a derived class that adds features to my object (derived is improper, agreed, but it helps understanding that derived is-a-kind of base, albeit not via inheritance).
struct foo_t {};
struct derived : decorator
{
using decorator::fun; // I want "native" fun, and decorated fun.
void fun(const foo_t&) {}
};
int main()
{
derived d;
d.fun(foo_t{});
}
Then C++14 came, with return type deduction, which allows to write things in a simpler way: remove the decltype part of the forwarding function:
struct decorator
{
base b;
template <typename... Args>
auto
fun(Args&&... args)
{
return b.fun(std::forward<Args>(args)...);
}
};
And then it breaks. Yes, at least according to both GCC and Clang, this:
template <typename... Args>
auto
fun(Args&&... args)
-> decltype(b.fun(std::forward<Args>(args)...))
{
return b.fun(std::forward<Args>(args)...);
}
};
is not equivalent to this (and the issue is not auto vs. decltype(auto)):
template <typename... Args>
auto
fun(Args&&... args)
{
return b.fun(std::forward<Args>(args)...);
}
};
The overload resolution seems to be completely different and it ends like this:
clang++-mp-3.5 -std=c++1y main.cc
main.cc:19:18: error: no viable conversion from 'foo_t' to 'unsigned int'
return b.fun(std::forward<Args>(args)...);
^~~~~~~~~~~~~~~~~~~~~~~~
main.cc:32:5: note: in instantiation of function template specialization
'decorator::fun<foo_t>' requested here
d.fun(foo_t{});
^
main.cc:7:20: note: passing argument to parameter here
void fun(unsigned) {}
^
I understand the failure: my call (d.fun(foo_t{})) does not match perfectly with the signature of derived::fun, which takes a const foo_t&, so the very eager decorator::fun kicks in (we know how Args&&... is extremely impatient to bind to anything that does not match perfectly). So it forwards this to base::fun which can't deal with foo_t.
If I change derived::fun to take a foo_t instead of const foo_t&, then it works as expected, which shows that indeed here the problem is that there is a competition between derived::fun and decorator::fun.
However why the heck does this show with return-type deduction??? And more precisely why was this behavior chosen by the committee?
To make things easier, on Coliru:
the version with decltype that works
the version with type deduction that fails
Thanks!
Just look at this call:
d.fun(foo_t{});
You create a temporary (i.e rvalue), passing it as argument to the function. Now what do you think happens?
It first attempts to bind to the argument Arg&&, as it can accept rvalue but due to invalid return type deduction (which again due to foo_t cannot convert into unsigned int, because of which b.fun(std::forward<Args>(args)...) turns out to be invalid expression), this function is rejected if you use the decltype(expr) as return type, as in this case SFINAE comes into picture. But if you use simply auto, then SFINAE doesn't come into picture and the error is classified to be a hard-error which results in compilation failure.
The second overload which accepts foo_t const& as argument is called if SFINAE works in the first case.

Deduce member function return type using a class member function object

Edit: I feel kind of silly now. The posted code actually works with ???=decltype(acc(base(i)))... The error was something else - highly confusing though. I will post a new question about that. Thank you for your help.
I have some code like this:
template<typename Base, typename Acc>
struct Foo
{
Base base;
Acc acc;
auto operator()(unsigned i) const -> decltype(???) // what is ???
{ return acc(base(i)); }
};
How do I get the correct return type?
I tried with decltype(acc(base(i))) but this gives an error (using GCC 4.6.3):
there are no arguments to ‘base’ that depend on a template parameter,
so a declaration of ‘base’ must be available
I have been troubled for hours or days around such problems. Typically gcc wants this-> but clang does not. In some cases Foo:: also helps but there have been cases where I have given up using the member names. The following is only using the type names and (though more verbose) I think will not have any problems with either:
template<typename Base, typename Acc>
struct Foo
{
Base base;
Acc acc;
template<typename S>
using result = typename std::result_of<S>::type;
auto operator()(unsigned i) const
-> result<const Acc(result<const Base(unsigned)>)>
{ return acc(base(i)); }
};
More generally, whenever decltype(member_name) is causing problems, you can safely use decltype(std::declval<member_type>()) where member_type is const-qualified if the member function using it is const.
Even more generally, if you have a member function that is &&, & or const& qualified, use member_type, member_type& or const member_type& respectively in such expressions.
I have never looked into what the standard says but in practice compilers treat expressions differently in trailing return types and inside function definitions when it comes to class members.

Isn't the template argument (the signature) of std::function part of its type?

Given the following code, what is the reason behind the ambiguity? Can I circumvent it or will I have to keep the (annoying) explicit casts?
#include <functional>
using namespace std;
int a(const function<int ()>& f)
{
return f();
}
int a(const function<int (int)>& f)
{
return f(0);
}
int x() { return 22; }
int y(int) { return 44; }
int main()
{
a(x); // Call is ambiguous.
a(y); // Call is ambiguous.
a((function<int ()>)x); // Works.
a((function<int (int)>)y); // Works.
return 0;
}
Interestingly, if I comment out the a() function with the function<int ()> parameter and call a(x) in my main, the compilation correctly fails because of the type mismatch between x and the argument function<int (int)> of the only a() function available. If the compiler fails in that case, why would there be any ambiguity when the two a() functions are present?
I've tried with VS2010 and g++ v. 4.5. Both give me the exact same ambiguity.
The problem is that both function<int()> and function<int(int)> are constructible from the same function. This is what the constructor declaration of std::function looks like in VS2010:
template<class _Fx>
function(_Fx _Func, typename _Not_integral<!_Is_integral<_Fx>::value, int>::_Type = 0);
Ignoring the SFINAE part, it is constructible from pretty much anything.
std::/boost::function employ a technique called type erasure, to allow arbitary objects/functions to be passed in, so long they satisfy the signature when being called. One drawback from that is, that you get an error in the deepest part of the implementation (where the saved function is being called) when supplying an object which can't be called like the signature wants it to, instead of in the constructor.
The problem can be illustrated with this little class:
template<class Signature>
class myfunc{
public:
template<class Func>
myfunc(Func a_func){
// ...
}
};
Now, when the compiler searches for valid functions for the overload set, it tries to convert the arguments if no perfect fitting function exists. The conversion can happen through the constructor of the parameter of the function, or through a conversion operator of the argument given to the function. In our case, it's the former.
The compiler tries the first overload of a. To make it viable, it needs to make a conversion. To convert a int(*)() to a myfunc<int()>, it tries the constructor of myfunc. Being a template that takes anything, the conversion naturally succeeds.
Now it tries the same with the second overload. The constructor still being the same and still taking anything given to it, the conversion works too.
Being left with 2 functions in the overload set, the compiler is a sad panda and doesn't know what to do, so it simply says the call is ambigious.
So in the end, the Signature part of the template does belong to the type when making declarations/definitions, but doesn't when you want to construct an object.
Edit:
With all my attention on answering the title-question, I totally forgot about your second question. :(
Can I circumvent it or will I have to keep the (annoying) explicit casts?
Afaik, you have 3 options.
Keep the cast
Make a function object of the appropriate type and pass that
function<int()> fx = x;
function<int(int)> fy = y;
a(fx);
a(fy);
Hide the tedious casting in a function and use TMP to get the right signature
The TMP (template metaprogramming) version is quite verbose and with boilerplate code, but it hides the casting from the client. An example version can be found here, which relies on the get_signature metafunction that is partially specialized on function pointer types (and provides a nice example how pattern matching can work in C++):
template<class F>
struct get_signature;
template<class R>
struct get_signature<R(*)()>{
typedef R type();
};
template<class R, class A1>
struct get_signature<R(*)(A1)>{
typedef R type(A1);
};
Of course, this needs to be extended for the number of arguments you want to support, but that is done once and then buried in a "get_signature.h" header. :)
Another option I consider but immediatly discarded was SFINAE, which would introduce even more boilerplate code than the TMP version.
So, yeah, that are the options that I know of. Hope one of them works for you. :)
I've seen this question come up one too many times. libc++ now compiles this code without ambiguity (as a conforming extension).
Overdue Update
This "extension" proved sufficiently popular that it was standardized in C++14 (though I was not personally responsible for getting that job done).
In hindsight, I did not get this extension exactly correct. Earlier this month (2015-05-09) the committee voted in LWG issue 2420 which effectively changes the definition of Callable so that if the std::function has a void return type it will ignore the return type of the wrapped functor, but still otherwise consider it Callable if everything else matches up, instead of considering it not Callable.
This post-C++14 tweak does not impact this particular example since the return types involved are consistently int.
Here's an example of how to wrap std::function in a class that checks invokability of its constructor parameters:
template<typename> struct check_function;
template<typename R, typename... Args>
struct check_function<R(Args...)>: public std::function<R(Args...)> {
template<typename T,
class = typename std::enable_if<
std::is_same<R, void>::value
|| std::is_convertible<
decltype(std::declval<T>()(std::declval<Args>()...)),
R>::value>::type>
check_function(T &&t): std::function<R(Args...)>(std::forward<T>(t)) { }
};
Use like this:
int a(check_function<int ()> f) { return f(); }
int a(check_function<int (int)> f) { return f(0); }
int x() { return 22; }
int y(int) { return 44; }
int main() {
a(x);
a(y);
}
Note that this isn't quite the same as overloading on function signature, as it treats convertible argument (and return) types as equivalent. For exact overloading, this should work:
template<typename> struct check_function_exact;
template<typename R, typename... Args>
struct check_function_exact<R(Args...)>: public std::function<R(Args...)> {
template<typename T,
class = typename std::enable_if<
std::is_convertible<T, R(*)(Args...)>::value>::type>
check_function_exact(T &&t): std::function<R(Args...)>(std::forward<T>(t)) { }
};
std::function<T> has a conversion ctor that takes an arbitrary type (i.e., something other than a T). Sure, in this case, that ctor would result in a type mismatch error, but the compiler doesn't get that far -- the call is ambiguous simply because the ctor exists.