简体   繁体   中英

Function signature differences in C++11

Considering C++11's lambdas with the following code,

template <typename M>
void call(void (*f)(M), M m)
{
  f(m);
}

int main()
{
  call<int>([](int n) { }, 42);          // OK

  int r;
  call<int>([&](int n) { r = n; }, 42);  // KO
}

is there a signature difference between the lambdas that makes the second one incompatible with the argument of call ?

I use g++ 4.6.1.

Side question: why can't the parameter be inferred if I write call([](int n) { }, 42); ?

Only a captureless lambda can be implicitly converted to function pointer.

A lambda that captures variables cannot be converted to a function pointer because it has state that needs to be maintained (the captured variables) and that state cannot be represented by a function pointer.

The type M cannot be inferred from the function arguments because a conversion is required to convert the lambda to a function pointer. That conversion inhibits template argument deduction. If you were to call the function call with an actual function (eg, void f(int) ), argument deduction would work just fine.

As James already answered, only captureless lambdas can be converted to function pointers. Lambdas that have state create functor objects that implement operator() , and member function pointers are incompatible with free function pointers.

When the compiler processes: [&](int n){ r = n; } [&](int n){ r = n; } it generates something like:

class __annonymous_lambda_type {
   int & r;
public:
   __annonymous_lambda_type( int & r ) : r(r) {}
   void operator()( int n ) const {
      r = n; 
   }
} __lambda_instatiation;

The class is required to store the state of the lambda, in this case the reference to the external object that will be modified when the lambda is executed. That void operator()(int) cannot be bound to a void (*)(int) .

On the other hand, if the lambda is stateless, it can be implemented as a free function, like in the case []( int n ) { std::cout << "Hi" << n << std::endl ; } []( int n ) { std::cout << "Hi" << n << std::endl ; }

void __annonymous_lambda_function( int n ) {
   std::cout << "Hi " << n << std::endl;
}

Because the lambda does not need to keep any state at all, and as such it can be kept as a plain function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM