Issue 2132: std::function ambiguity (original) (raw)
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.
2132. std::function ambiguity
Section: 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
void f(std::function<void()>) {} void f(std::function<void(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.
Daniel: During the preparation of N3123it turned out that there are no longer reasons to refer to INVOKE as a conceptually entity alone, its real implementation as a function template invokeis 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 theresult_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 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](lwg-defects.html#1234 ""Do the right thing" and NULL (Status: C++11)")(i).
It would be possible to apply similar constraints to the member signatures
template function& operator=(reference_wrapper);
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
Ais recommended, because they are already part of the Allocator requirements. Similar clean-up has been suggested by 2070(i) — _end comment_]template function(F f);
template<class F, class A> function(allocator_arg_t, const A& a, F f);-7- Requires:
Fshall beCopyConstructible.fshall be Callable (22.10.17.3 [func.wrap.func]) for argument typesArgTypesand return typeR. The copy constructor and destructor ofAshall not throw exceptions.-?- Remarks: These constructors shall not participate in overload resolution unless
fis Callable (22.10.17.3 [func.wrap.func]) for argument typesArgTypes...and return typeR.[…]
template function& operator=(F&& f);
-18- Effects:
function(std::forward<F>(f)).swap(*this);-19- Returns:
*this-?- Remarks: This assignment operator shall not participate in overload resolution unless
declval<typename decay<F>::type&>()is Callable (22.10.17.3 [func.wrap.func]) for argument typesArgTypes...and return typeR.