C ++ лямбда-ограничения захвата - PullRequest
6 голосов
/ 12 марта 2012

Можно ли ограничить тип захвата лямбды, заданной в качестве параметра?
Например, можно ли брать только лямбды, которые ничего не фиксируют по ссылке?

template <typename F>
void f(const F& lambda) // F must be a lambda that do not capture by ref
{
  :::
}

Ответы [ 3 ]

5 голосов
/ 15 марта 2012

MSalters отмечает, что «лямбда без захвата может быть преобразована в указатель на функцию».Что это значит?Лямбда-объект будет соответствовать указателю на тип параметра функции.

Сложно преобразовать лямбда-тип в указатель на функцию.Вот моя попытка совместимой реализации.Это немного хакерски.

#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
}

Это не примет указатели функций в качестве прямых аргументов, так как параметр шаблона должен преобразовываться в функтор.Вы можете сделать это, предоставив специализацию для ptmf_to_pf, которая принимает указатель на типы функций.

Кроме того, как показывает демонстрация, он не будет принимать лямбда-выражения, которые собирают что-либо по значению, а такжессылка.В C ++ нет способа сделать это ограничение таким конкретным.

5 голосов
/ 12 марта 2012

Возможно, вы неправильно понимаете поведение захвата лямбда-выражений: объект замыкания аналогичен объекту функтора, поэтому

struct Fun
{
    Fun (int & a) : n(a) { }
    int operator()(...) { ... }
private:
    int & n;
};

int q;
Fun f(q);
f(...);

точно так же, как

int q;
auto f = [&q](...) -> int { ... };
f(...);

После создания объекта замыкания все захват и привязка завершаются и навсегда блокируются в объекте.

Если вы теперь передадите объект в другое место, например, call_me(f), функция получателя не будет связана с конструкцией функтора или объекта замыкания.

3 голосов
/ 12 марта 2012

Косвенный взлом: только не захватывая лямбда-выражения можно преобразовать в указатель на функцию.Конечно, это также относится ко многим F типам, которые совсем не являются лямбдами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...