Wrap overloaded function via std::function
That is ambiguous situation.
To disambiguate it, use explicit cast as:
typedef int (*funtype)(const std::string&);
std::function<int(const std::string&)> func=static_cast<funtype>(test);//cast!
Now the compiler would be able to disambiguate the situation, based on the type in the cast.
Or, you can do this:
typedef int (*funtype)(const std::string&);
funtype fun = test; //no cast required now!
std::function<int(const std::string&)> func = fun; //no cast!
So why std::function<int(const std::string&)>
does not work the way funtype fun = test
works above?
Well the answer is, because std::function
can be initialized with any object, as its constructor is templatized which is independent of the template argument you passed to std::function
.
std::function fails to distinguish overloaded functions
It's obvious to us which function you intend to be chosen, but the compiler has to follow the rules of C++ not use clever leaps of logic (or even not so clever ones, as in simple cases like this!)
The relevant constructor of std::function
is:
template<class F> function(F f);
which is a template that accepts any type.
The C++14 standard does constrain the template (since LWG DR 2132) so that it:
shall not participate in overload resolution unless
f
is Callable (20.9.12.2) for argument typesArgTypes...
and return typeR
.
which means that the compiler will only allow the constructor to be called when Functor
is compatible with the call signature of the std::function
(which is void(int, int)
in your example). In theory that should mean that void add(A, A)
is not a viable argument and so "obviously" you intended to use void add(int, int)
.
However, the compiler can't test the "f
is Callable for argument types ..." constraint until it knows the type of f
, which means it needs to have already disambiguated between void add(int, int)
and void add(A, A)
before it can apply the constraint that would allow it to reject one of those functions!
So there's a chicken and egg situation, which unfortunately means that you need to help the compiler out by specifying exactly which overload of add
you want to use, and then the compiler can apply the constraint and (rather redundantly) decide that it is an acceptable argument for the constructor.
It is conceivable that we could change C++ so that in cases like this all the overloaded functions are tested against the constraint (so we don't need to know which one to test before testing it) and if only one is viable then use that one, but that's not how C++ works.
Overload resolution with std::function
In C++11...
Let's take a look at the specification of the constructor template of std::function
(which takes any Callable): [func.wrap.func.con]/7-10
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 Requires:
F
shall beCopyConstructible
.f
shall beCallable
(20.10.11.2) for argument typesArgTypes
and return type
R
. The copy constructor and destructor ofA
shall not throw
exceptions.8 Postconditions:
!*this
if any of the following hold:
f
is aNULL
function pointer.f
is aNULL
pointer to member.F
is an instance of the function class template, and!f
9 Otherwise,
*this
targets a copy off
initialized withstd::move(f)
. [left out a note here]10 Throws: shall not throw exceptions when
f
is a function pointer or areference_wrapper<T>
for someT
. Otherwise, may throw
bad_alloc
or any exception thrown byF
’s copy or move constructor.
Now, constructing, or attempting to construct (for overload resolution) a std::function<void(int)>
from a [](){}
(i.e. with signature void(void)
) violates the requirements of std::function<void(int)>
's constructor.
[res.on.required]/1
Violation of the preconditions specified in a function’s Requires: paragraph results in undefined behavior unless the function’s Throws: paragraph specifies throwing an exception when the precondition is violated.
So, AFAIK, even the result of the overload resolution is undefined. Therefore, both versions of g++/libstdc++ are complying in this aspect.
In C++14, this has been changed, see LWG 2132. Now, the converting constructor template of std::function
is required to SFINAE-reject incompatible Callables (more about SFINAE in the next chapter):
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 Requires:
F
shall beCopyConstructible
.8 Remarks: These constructors shall not participate in overload
resolution unlessf
is Callable (20.9.11.2) for argument types
ArgTypes...
and return typeR
.[...]
The "shall not participate in overload resolution" corresponds to rejection via SFINAE. The net effect is that if you have an overload set of functions foo
,
void foo(std::function<void(double)>);
void foo(std::function<void(char const*)>);
and a call-expression such as
foo([](std::string){}) // (C)
then the second overload of foo
is chosen unambiguously: Since std::function<F>
defines F
as its interface to the outside, the F
defines which argument types are passed into std::function
. Then, the wrapped function object has to be called with those arguments (argument types). If a double
is passed into std::function
, it cannot be passed on to a function taking a std::string
, because there's no conversion double
-> std::string
.
For the first overload of foo
, the argument [](std::string){}
is therefore not considered Callable for std::function<void(double)>
. The constructor template is deactivated, hence there's no viable conversion from [](std::string){}
to std::function<void(double)>
. This first overload is removed from the overload set for resolving the call (C), leaving only the second overload.
Note that there's been a slight change to the wording above, due to LWG 2420: There's an exception that if the return type R
of a std::function<R(ArgTypes...)>
is void
, then any return type is accepted (and discarded) for the Callable in the constructor template mentioned above. For example, both []() -> void {}
and []() -> bool {}
are Callable for std::function<void()>
. The following situation therefore produces an ambiguity:
void foo(std::function<void()>);
void foo(std::function<bool()>);
foo([]() -> bool {}); // ambiguous
The overload resolution rules don't try to rank among different user-defined conversions, and hence both overloads of foo
are viable (first of all) and neither is better.
How can SFINAE help here?
Note when a SFINAE-check fails, the program isn't ill-formed, but the function isn't viable for overload resolution. For example:
#include <type_traits>
#include <iostream>
template<class T>
auto foo(T) -> typename std::enable_if< std::is_integral<T>::value >::type
{ std::cout << "foo 1\n"; }
template<class T>
auto foo(T) -> typename std::enable_if< not std::is_integral<T>::value >::type
{ std::cout << "foo 2\n"; }
int main()
{
foo(42);
foo(42.);
}
Similarly, a conversion can be made non-viable by using SFINAE on the converting constructor:
#include <type_traits>
#include <iostream>
struct foo
{
template<class T, class =
typename std::enable_if< std::is_integral<T>::value >::type >
foo(T)
{ std::cout << "foo(T)\n"; }
};
struct bar
{
template<class T, class =
typename std::enable_if< not std::is_integral<T>::value >::type >
bar(T)
{ std::cout << "bar(T)\n"; }
};
struct kitty
{
kitty(foo) {}
kitty(bar) {}
};
int main()
{
kitty cat(42);
kitty tac(42.);
}
Unresolved overloaded function type in std::transfrom
I don't want to believe that the asker didn't know they are defining two functions with the same name degrees
, so I'll give another shade to my answer.
How is it possible, in this call
std::transform(val.begin(), val.end(), std::back_inserter(out), degrees);
that degrees
is not known? I mean, std::transform
should try to apply degrees
to each element in val
, and since each of those elements is a double
, isn't it obvious that transform should make use of the first overload, the one which takes a double
?
As convincing as this motivation might be, though, it would require the compiler to delay/defer the decision of what degrees
should be called to the moment it's actually called, i.e. not at the call site of std::transform
, but inside std::transform
(specifically, when evaluating the expression unary_op(*first1++)
in this possible implementation on the cppreference doc page).
This is simply not possible, as the rules are that the compiler must know at the call site of a function what its arguments are. With reference to the example, at the call site of std::transform
the compiler has no idea which of the overloads of degree
is needed.
One way around is to wrap degrees
in a function object with overloaded operator()
, as suggested by 463035818_is_not_a_number; doing so, the object degrees
would be known at std::transform
call site, and only inside std::transform
, at the call site of the object's operator()
would the compiler have to choose between the overloads of operator()
.
In C++11, is it possible to wrap a template function in a std::function?
You can't wrap a generic function in a specific instance of std::function
, which is what you asked for.
You can, however, wrap a fully-specified instance of a generic function, which is what your code is actually trying to do:
template <typename T>
auto sum(T const& a, T const& b) -> decltype(a+b)
{
return a + b;
}
#include <functional>
#include <iostream>
int main()
{
std::function<int(int,int)> intsum =
std::bind(sum<int>,
std::placeholders::_1, std::placeholders::_2);
auto mysum = intsum(2, 4);
std::cout << mysum << std::endl;
}
Or more simply
std::function<int(int,int)> intsum = sum<int>;
Or of course if you don't really need to wrap it, just:
auto mysum = sum(2, 4);
Using std::invoke when a function is overloaded
There are two example solutions:
std::invoke(static_cast<void(S::*)(int)>(&S::foo), s, 1);
std::invoke([&s]() { s.foo(1); });
Related Topics
Boost.Python: Wrap Functions to Release the Gil
Debug Assertion Failed! Expression: _Block_Type_Is_Valid
Cmake Link Library Target Link Error
Why Does Adding 0 to the End of Float Literal Change How It Rounds (Possible Gcc Bug)
Element Count of an Array in C++
Or Is Not Valid C++:Why Does This Code Compile
Use Const Wherever Possible in C++
Why Isn't Operator Overloading for Pointers Allowed to Work
Potential Problem in "Swapping Values of Two Variables Without Using a Third Variable"
Why Does Makeintresource() Work
Why Is It a Compile Error to Assign the Address of an Array to a Pointer "My_Pointer = &My_Array"
Create Shared_Ptr to Stack Object