Шаблонные функции и именованные лямбды с автоматическими параметрами

Каковы различия между

template <typename T> void func( T t ) { /* ... */ }

и альтернатива C ++ 14, использующая лямбда с автоматическими параметрами?

auto func = []( auto t ) { /* ... */ }

Какой из них должен быть предпочтительным?

11

Решение

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

Второе, если предположить, что оно появляется в области имен, это глобальный объект с оператором вызова шаблонной функции. Он не может быть специализированным или перегруженным (глобальные переменные конфликтуют с функциями, они не перегружают их). Он не может быть найден ADL (ADL находит только функции и шаблоны функций). Если вы используете оператор адреса для него, вы получите адрес объекта, который довольно бесполезен. Сам объект может быть преобразован в указатель на функцию, если компилятор может определить аргументы; Вы не можете предоставить их явно.

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

auto func(auto t) { ... }
7

Другие решения

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

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

//specialization : possible only in case of template!
template<> void func(MyClass obj) { /* ... */ }

Вы не можете сделать это с лямбдами!

8

N3337, [expr.prim.lambda] / 3:

Тип лямбда-выражения (который также является типом
объект замыкания) — это уникальный, безымянный тип класса nonunion, называемый
тип закрытия — свойства которого описаны ниже. Этот тип класса
не является агрегатом (8.5.1). Тип закрытия объявлен в
наименьшая область блока, область класса или область пространства имен, которая содержит
соответствующее лямбда-выражение.

Этот тип закрытия останется классом. Но его перегруженный оператор вызова функции будет шаблон операторской функции, позволяя разные специализации. Кроме того, в отличие от шаблонов функций, вы можете неявно преобразовывать объект замыкания в указатель на функцию. Это действительно удобно, не так ли?
Цитируя N3559, это будет выглядеть примерно так:

Для общего лямбда L:

int(*fp)(int, char) = [](auto a, auto b){return a+b;};

Тип закрытия

struct/*anonymous*/
{
template<class A,class B>
auto operator()(A a,B b) const
{
return a+b;
}

private:
template<class A,class B>
static auto __invoke(A a,B b)
{
return a+b;
}

template<class A,class B,class R>
using fptr_t = R(*)(A,B);

public:

template<class A,class B,class R>
operator fptr_t<R,A,B>() const
{
return &__invoke<A,B>; // Fixed that manually, they forgot to qualify the template name
}
} L;

int(*fp)(int,char) = L;

(Будет обычный вывод аргумента шаблона)

2
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector