Как работает generic lambda в C++14?

Как работает общая лямбда (auto ключевое слово как тип аргумента) в стандарте C++14?

основан ли он на шаблонах C++, где для каждого другого типа аргумента компилятор генерирует новую функцию с тем же телом, но замененными типами (полиморфизм времени компиляции) или он больше похож на дженерики Java (стирание типа)?

пример кода:

auto glambda = [](auto a) { return a; };

3 ответов


общие лямбды были введены в C++14.

просто тип закрытия, определенный лямбда-выражением, будет иметь templated оператор вызова, а не обычный, не шаблонный оператор вызова C++11лямбда (конечно, когда auto появляется хотя бы один раз в списке параметров).

так что твой пример:

auto glambda = [] (auto a) { return a; };

сделает glambda экземпляр этого тип:

class /* unnamed */
{
public:
    template<typename T>
    T operator () (T a) const { return a; }
};

в пункте 5.1.2 / 5 проекта стандарта C++14 n3690 указывается, как определяется оператор вызова типа замыкания данного лямбда-выражения:

тип закрытия для неродового лямбда-выражения имеет открытый оператор вызова встроенной функции (13.5.4) чьи параметры и тип возвращаемого значения описываются предложением parameter-declaration - и trailing-return-type соответственно. для общей лямбды, тип закрытия имеет открытый вызов встроенной функции шаблон члена оператора (14.5.2), список параметров-шаблонов которого состоит из одного изобретенного типа template-parameter для каждого появления auto в предложении parameter-declaration-Lambda в порядке появления. Изобретенный тип template-parameter является пакетом параметров, если соответствующий параметр-declaration объявляет пакет параметров функции (8.3.5). Возвращаемые параметры типа и функции вызова функции шаблон оператора являются производными от типа и параметра-declarationclause трейлинг-возврата лямбда-выражения заменяя каждое вхождение auto в спецификаторах decl предложения parameter-declaration на название соответствующего придуманного шаблона-параметра.

и наконец:

похоже ли это на шаблоны, где для каждого другого типа аргумента компилятор генерирует функции с тем же телом, но измененными типами или он больше похож на Java генерики?

как объясняется в предыдущем абзаце, общие лямбды - это просто синтаксический сахар для уникальных неназванных функторов с шаблонным оператором вызова. Это должно ответить на ваш вопрос :)


к сожалению, они не являются частью C++11 (http://ideone.com/NsqYuq):

auto glambda = [](auto a) { return a; };

int main() {}

С g++ 4.7:

prog.cpp:1:24: error: parameter declared ‘auto’
...

, как это может быть реализовано в C++14 в соответствии с предложение Portland для общих лямбд:

[](const& x, & y){ return x + y; }

это дало бы по большей части обычное создание анонимного класса функтора, но с отсутствием типов компилятор испустил бы шаблонный член -operator():

struct anonymous
{
    template <typename T, typename U>
    auto operator()(T const& x, U& y) const -> decltype(x+y)
    { return x + y; }
};

или согласно более новому предложению предложение для общих (полиморфных) лямбда-выражений

auto L = [](const auto& x, auto& y){ return x + y; };

--->

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;

так что да, для каждой перестановки параметров возникнет новый экземпляр, однако члены этого функтора все равно будут разделены (т. е. захваченные аргументы).


это предлагаемая функция C++14 (не в C++11), аналогичная (или даже эквивалентная) шаблонам. Например, N3559 обеспечивает такой пример:

например, это общее лямбда-выражение, содержащее оператор:

auto L = [](const auto& x, auto& y){ return x + y; };

может привести к созданию типа закрытия и объекта, который ведет себя аналогично приведенной ниже структуре:

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;