Reputation: 10917
Is it possible to constrain the type of capture of a lambda given as parameter ?
For example, Is it possible to take only lambdas that don't capture anything by reference ?
template <typename F>
void f(const F& lambda) // F must be a lambda that do not capture by ref
{
:::
}
Upvotes: 6
Views: 1249
Reputation: 137810
MSalters notes that "non-capturing lambda's can be converted to a pointer-to-function." What does this mean? The lambda object will match a pointer to function parameter type.
It's tricky to translate the lambda type to a pointer-to-function. Here is my attempt at a compliant implementation. It's slightly hackish.
#include <type_traits>
template< typename fn >
struct ptmf_to_pf;
template< typename r, typename c, typename ... a >
struct ptmf_to_pf< r (c::*) ( a ... ) const >
{ typedef r (* type)( a ... ); };
// Use SFINAE to hide function if lambda is not convertible to function ptr.
// Only check that the conversion is legal, it never actually occurs.
template< typename lambda >
typename std::enable_if< std::is_constructible<
typename ptmf_to_pf< decltype( &lambda::operator() ) >::type,
lambda >::value >::type
f( lambda arg ) {
arg( "hello " );
arg( "world\n" );
}
#include <iostream>
int main() {
int x = 3;
f( []( char const *s ){ std::cout << s; } ); // OK
f( [=]( char const *s ){ std::cout << s; } ); // OK
f( [=]( char const *s ){ std::cout << s << x; } ); // error
}
This will not accept function pointers as direct arguments, since the template parameter needs to resolve to a functor. You could make it do so by providing a specialization for ptmf_to_pf
that accepts pointer to function types.
Also, as the demo shows, it won't accept lambdas that capture anything by value, as well as by reference. There is no way in C++ to make the restriction so specific.
Upvotes: 5
Reputation: 179819
Indirect hack: Only non-capturing lambda's can be converted to a pointer-to-function. Of course, that also covers a lot of F
types that aren't lambda's at all.
Upvotes: 3
Reputation: 477040
Maybe you're misunderstanding the capturing behaviour of lambda expressions: A closure object is just like a functor object spelt out, so
struct Fun
{
Fun (int & a) : n(a) { }
int operator()(...) { ... }
private:
int & n;
};
int q;
Fun f(q);
f(...);
is exactly the same as
int q;
auto f = [&q](...) -> int { ... };
f(...);
Once the closure object is constructed, all the capturing and binding is finished and forever locked into the object.
If you now pass the object on to some other place, like call_me(f)
, then the recipient function has no connection with the construction of the functor or closure object.
Upvotes: 5