1292. std::function should support all callable types

Section: 22.10.17.3.2 [func.wrap.func.con] Status: C++11 Submitter: Daniel Krügler Opened: 2009-12-19 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [func.wrap.func.con].

View all issues with C++11 status.

Discussion:

Some parts of the specification of std::function is unnecessarily restricted to a subset of all callable types (as defined in 22.10.3 [func.def]/3), even though the intent clearly is to be usable for all of them as described in 22.10.17.3 [func.wrap.func]/1. This argument becomes strengthened by the fact that current C++0x-compatible compilers work fine with them:

#include <functional>
#include <iostream>

struct A
{
  int foo(int i) const {return i+1;}
};

struct B
{
  int mem;
};

int main()
{
  std::function<int(const A&, int)> f(&A::foo);
  A a;
  std::cout << f(a, 1) << '\n';
  std::cout << f.target_type().name() << '\n';
  typedef int (A::* target_t)(int) const;
  target_t* p = f.target<target_t>();
  std::cout << (p != 0) << '\n';
  std::function<int(B&)> f2(&B::mem);
  B b = { 42 };
  std::cout << f2(b) << '\n';
  std::cout << f2.target_type().name() << '\n';
  typedef int (B::* target2_t);
  target2_t* p2 = f2.target<target2_t>();
  std::cout << (p2 != 0) << '\n';
}

The problematic passages are 22.10.17.3.2 [func.wrap.func.con]/10:

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

...

10 Postconditions: !*this if any of the following hold:

because it does not consider pointer to data member and all constraints based on function objects which like 22.10.17.3 [func.wrap.func]/2 or 22.10.17.3.6 [func.wrap.func.targ]/3. The latter two will be resolved by the proposed resolution of 870 and are therefore not handled here.

[ Post-Rapperswil: ]

Moved to Tentatively Ready after 5 positive votes on c++std-lib.

[ Adopted at 2010-11 Batavia ]

Proposed resolution:

Change 22.10.17.3.2 [func.wrap.func.con]/10+11 as indicated:

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

...

10 Postconditions: !*this if any of the following hold:

11 Otherwise, *this targets a copy of f or, initialized with std::move(f) if f is not a pointer to member function, and targets a copy of mem_fn(f) if f is a pointer to member function. [Note: implementations are encouraged to avoid the use of dynamically allocated memory for small function objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]