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 unlessFshall 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.fis 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.