This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.
std::function
ambiguitySection: 22.10.17.3.2 [func.wrap.func.con] Status: C++14 Submitter: Ville Voutilainen Opened: 2012-02-28 Last modified: 2016-01-28
Priority: 2
View all other issues in [func.wrap.func.con].
View all issues with C++14 status.
Discussion:
Consider the following:
#include <functional> void f(std::function<void()>) {} void f(std::function<void(int)>) {} int main() { f([]{}); f([](int){}); }
The calls to f
in main
are ambiguous. Apparently because the
conversion sequences to std::function
from the lambdas are identical.
The standard specifies that the function object given to std::function
"shall be Callable (20.8.11.2) for argument types ArgTypes
and
return type R
." It doesn't say that if this is not the case, the
constructor isn't part of the overload set.
invoke
is possible but was deferred for a later point in time. Defining a type trait for
the Callable requirement would also be possible, so there seem to be no technical
reasons why the template constructor of std::function
should not be
constrained. The below suggested wording does this without introducing a special
trait for this. This corresponds to the way that has been used to specify the
result_of
trait. Note that the definition of the Callable
requirement is perfectly suitable for this, because it is a pure syntactically
based requirement and can be directly transformed into a constrained template.
The suggested resolution also applies such wording to the "perfectly forwarding"
assignment operator
template<class F> function& operator=(F&&);
The positive side-effect of this is that it automatically implements a solution to a problem similar to that mentioned in issue 1234(i).
It would be possible to apply similar constraints to the member signaturestemplate<class F> function& operator=(reference_wrapper<F>); template<class F, class A> void assign(F&&, const A&);
as well. At this point there does not seem to be a pestering reason to do so.
[2012-10 Portland: Move to Review]
STL: This is a real issue, but does not like a resolution relying on a SFINAEable metafunction that is not specified and available to the users.
packaged_task
has the same issue.
STL strongly wants to see an is_callable
type trait to clarify the proposed wording.
Jeremiah concerned about holding up what appears to be a correct resolution for a hypothetical better one later - the issue is real.
Why must f
by CopyConstructible? Surely MoveConstructible would be sufficient?
Answer: because function
is CopyConstructible, and the bound functor is type-erased
so must support all the properties of function
itself.
Replace various applications of declval
in the proposed resolution with simply using
the passed functor object, f
.
Alisdair to apply similar changes to packaged_task
.
[2012-11-09, Vicente J. Botet Escriba provides another example]
Consider the following:
class AThreadWrapper { public: explicit operator std::thread(); ... }; std::thread th = std::thread(AThreadWrapper); // call to conversion operator intended
The call to the conversion operator is overloaded with the thread constructor. But thread constructor requirement
makes it fail as AThreadWrapper
is not a Callable and the compiler tries to instantiate the thread
constructor and fails.
[2014-02-14 Issaquah meeting: Move to Immediate]
Proposed resolution:
This wording is relative to N3376.
Change the following paragraphs in 22.10.17.3.2 [func.wrap.func.con]:
[Editorial comment: The removal of the seemingly additional no-throw
requirements of copy constructor and destructor of A
is recommended,
because they are already part of the Allocator requirements. Similar clean-up
has been suggested by 2070(i) — end comment]
template<class F> function(F f); template<class F, class A> function(allocator_arg_t, const A& a, F f);-7- Requires:
-?- Remarks: These constructors shall not participate in overload resolution unlessF
shall beCopyConstructible
.f
shall be Callable (22.10.17.3 [func.wrap.func]) for argument typesArgTypes
and return typeR
. The copy constructor and destructor ofA
shall not throw exceptions.f
is Callable (22.10.17.3 [func.wrap.func]) for argument typesArgTypes...
and return typeR
.[…]
template<class F> function& operator=(F&& f);-18- Effects:
-19- Returns:function(std::forward<F>(f)).swap(*this);
*this
-?- Remarks: This assignment operator shall not participate in overload resolution unlessdeclval<typename decay<F>::type&>()
is Callable (22.10.17.3 [func.wrap.func]) for argument typesArgTypes...
and return typeR
.