The constructor for std::function<...>
is templated because it has to be able to support any function-like input type. There's no single type to try to deduce to, so your overloads are all possible to construct with; it wouldn't be until later into compilation later that an error arose for a type mismatch.
You could do this:
GetInfo(item, static_cast<double(*)(ITEM*)>(GetLength));
To explicitly discard the other overloads.
In other words, it's the same reason this won't work:
void foo(int);
void foo(void*);
struct bar
{
template <typename T>
bar(T f)
{
f(5);
}
};
bar b(foo);
Even though the constructor body for bar
will only work with void foo(int)
,
it wants to support any function where f(5)
will work so the argument type is templated. This allows any function to work in that place, which means the compiler cannot deduce a single best overload to use.
I think that one language-level solution is for an overload set to actually be a functor itself. That is, given:
void foo(int);
void foo(void*);
template <typename T>
double foo(int, T);
Naming foo
(as in bar(foo)
or even just foo(5)
) results in an instance of this type:
struct __foo_overload_set // internal
{
// forwarders
void operator()(int __arg0) const
{
// where __foo0 is the zeroth overload, etc...
return __foo0(__arg0);
}
void operator()(void* __arg0) const
{
return __foo1(__arg0);
}
template <typename __Arg1>
double operator()(int __arg0, __Arg1&& __arg1) const
{
return __foo2(__arg0, std::forward<__Arg1>(__arg1));
}
// converters
typedef void(*__foo0_type)(int);
operator __foo0_type() const
{
return __foo0;
}
typedef void(*__foo1_type)(void*);
operator __foo1_type() const
{
return __foo1;
}
template <typename T>
struct __foo2_type
{
typedef void(*type)(int, T);
};
template <typename T>
operator typename __foo2_type<T>::type() const
{
return __foo2;
}
};
Which, being callable itself, will compile in the context we want. (AFAIK, it does not introduce any ambiguities that don't already exist, though it's completely untested.)