Могут ли использоваться шаблоны лямбда?
В С++ 11 есть способ шаблона лямбда-функции? Или это по своей сути слишком специфично для шаблонов?
Я понимаю, что вместо этого могу определить классический шаблонный класс/функтор, но вопрос больше похож: позволяет ли язык использовать шаблонные лямбда-функции?
Ответы
Ответ 1
UPDATE 2014: С++ 14 были выпущены в этом году и теперь предоставляют Polymorphic lambdas с тем же синтаксисом, что и в этом примере. Некоторые основные компиляторы уже реализуют его.
У него стоит (в С++ 11), к сожалению нет. Полиморфные лямбды были бы превосходны с точки зрения гибкости и мощности.
Первоначальная причина, по которой они оказались мономорфными, была из-за понятий. Понятия затруднили эту ситуацию кода:
template <Constraint T>
void foo(T x)
{
auto bar = [](auto x){}; // imaginary syntax
}
В ограниченном шаблоне вы можете вызывать только другие ограниченные шаблоны. (В противном случае ограничения не могут быть проверены.) Может ли foo
вызвать bar(x)
? Какие ограничения имеют лямбда (параметр для него - всего лишь шаблон, в конце концов)?
Понятия не были готовы к решению такого рода вещей; для этого потребовалось бы больше материала, такого как late_check
(где концепция не проверялась до вызова) и прочее. Проще было просто бросить все это и придерживаться мономорфных лямбдов.
Однако, с удалением понятий из С++ 0x, полиморфные лямбды снова становятся простым предложением. Однако я не могу найти для этого никаких предложений.: (
Ответ 2
С++ 11 lambdas нельзя шаблонировать, как указано в других ответах, но decltype()
, похоже, помогает при использовании лямбда в шаблоном классе или функции.
#include <iostream>
#include <string>
using namespace std;
template<typename T>
void boring_template_fn(T t){
auto identity = [](decltype(t) t){ return t;};
std::cout << identity(t) << std::endl;
}
int main(int argc, char *argv[]) {
std::string s("My string");
boring_template_fn(s);
boring_template_fn(1024);
boring_template_fn(true);
}
Печать
My string
1024
1
Я нашел, что эта техника помогает при работе с шаблоном кода, но осознать, что это все равно означает, что сами лямбда не могут быть шаблонами.
Ответ 3
В С++ 11 нельзя использовать шаблонные функции lambda, но в следующей версии стандарта ISO С++ (часто называемой С++ 14) эта функция будет введена. [Источник]
Пример использования:
auto get_container_size = [] (auto container) { return container.size(); };
Обратите внимание, что хотя синтаксис использует ключевое слово auto
, вывод типа не будет использовать правила вывода типа auto
, а вместо этого использовать правила вывода аргумента шаблона. Также см. Предложение для общих лямбда-выражений (и обновление).
Ответ 4
Я знаю, что этот вопрос касается С++ 11. Тем не менее, для тех, кто googled и приземлился на этой странице, шаблонные lambdas теперь поддерживаются в С++ 14 и идут по имени Generic Lambdas.
[info] Большинство популярных компиляторов теперь поддерживают эту функцию. Microsoft Visual Studio 2015 поддерживает. Clang поддерживает. Поддержка GCC.
Ответ 5
Интересно, что об этом:
template <class something>
inline std::function<void()> templateLamda() {
return [](){ std::cout << something.memberfunc() };
}
Я использовал похожий код, похожий на этот, для создания шаблона и задаюсь вопросом, будет ли компилятор оптимизировать функцию "wrapping".
Ответ 6
Взгляните на Boost.Phoenix для полиморфных лямбда: http://www.boost.org/doc/libs/1_44_0/libs/spirit/phoenix/doc/html/index.html
Не требует С++ 0x, кстати:)
Ответ 7
Существует расширение gcc, которое позволяет лямбда-шаблоны:
// create the widgets and set the label
base::for_each(_widgets, [] <typename Key_T, typename Widget_T>
(boost::fusion::pair<Key_T, Widget_T*>& pair) -> void {
pair.second = new Widget_T();
pair.second->set_label_str(Key_T::label);
}
);
где _widgets
есть std::tuple< fusion::pair<Key_T, Widget_T>... >
Ответ 8
Я не уверен, почему никто этого не предложил, но вы можете написать шаблонную функцию, которая возвращает лямбда-функции. Следующее решение моей проблемы, причина, по которой я пришел на эту страницу:
template <typename DATUM>
std::function<double(DATUM)> makeUnweighted() {
return [](DATUM datum){return 1.0;};
}
Теперь, когда мне нужна функция, которая принимает заданный тип аргумента (например, std::string
), я просто говорю
auto f = makeUnweighted<std::string>()
и теперь f("any string")
возвращает 1.0
.
Это пример того, что я подразумеваю под "шаблонной лямбда-функцией". (Этот конкретный случай используется для автоматического предоставления инертной функции взвешивания, когда кто-то не хочет взвешивать свои данные, какими бы ни были их данные.)
Ответ 9
Вот одно решение, которое включает в себя обертывание lamba в структуре:
template <typename T>
struct LamT
{
static void Go()
{
auto lam = []()
{
T var;
std::cout << "lam, type = " << typeid(var).name() << std::endl;
};
lam();
}
};
Чтобы использовать do:
LamT<int>::Go();
LamT<char>::Go();
#This prints
lam, type = i
lam, type = c
Основная проблема с этим (помимо дополнительной набрав), вы не можете вставлять это определение структуры внутри другого метода или вы получаете (gcc 4.9)
error: a template declaration cannot appear at block scope
Я также попытался сделать это:
template <typename T> using LamdaT = decltype(
[](void)
{
std::cout << "LambT type = " << typeid(T).name() << std::endl;
});
С надеждой, что я могу использовать его так:
LamdaT<int>();
LamdaT<char>();
Но я получаю ошибку компилятора:
error: lambda-expression in unevaluated context
Так что это не сработает... но даже если бы он скомпилировал, это было бы ограничено
потому что нам все равно придется использовать "использование LamdaT" в области файлов
(потому что это шаблон), который поражает цель лямбда.