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

Daniel: During the preparation of N3123 it turned out that there are no longer reasons to refer to INVOKE as a conceptually entity alone, its real implementation as a function template `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.

It would be possible to apply similar constraints to the member signatures

>     template<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.

1. 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 — end comment]

   >     template<class F> function(F f);
   >     template<class F, class A> function(allocator_arg_t, const A& a, F f);

   > > -7- Requires: `F` shall be `CopyConstructible`. `f` shall be Callable (22.10.17.3 [func.wrap.func]) for argument types `ArgTypes` and return type `R`. The copy constructor and destructor of `A` shall not throw exceptions.

   > > -?- Remarks: These constructors shall not participate in overload resolution unless `f` is Callable (22.10.17.3 [func.wrap.func]) for argument types `ArgTypes...` and return type `R`.

   > […]

   >     template<class F> 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 types `ArgTypes...` and return type `R`.