Как использовать лямбда-выражение в качестве параметра шаблона?
Автор вопроса: CommunityОтветов: 4
Как использовать лямбда-выражение в качестве параметра шаблона? Например. как класс сравнения, инициализирующий std :: set.
Следующее решение должно работать, поскольку лямбда-выражение просто создает анонимную структуру, которая должна подходить в качестве параметра шаблона. Однако порождает много ошибок.
Пример кода:
struct A {int x; int y;};
std::set <A, [](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
} > SetOfA;
Вывод ошибок (я использую компилятор g ++ 4.5.1 и флаг компиляции --std = c ++ 0x):
error: ‘lhs’ cannot appear in a constant-expression
error: ‘.’ cannot appear in a constant-expression
error: ‘rhs’ cannot appear in a constant-expression
error: ‘.’ cannot appear in a constant-expression
At global scope:
error: template argument 2 is invalid
Это ожидаемое поведение или ошибка в GCC?
ИЗМЕНИТЬ
Как кто-то заметил, я неправильно использую лямбда-выражения, поскольку они возвращают экземпляр анонимной структуры, на которую они ссылаются.
Однако исправление этой ошибки не решает проблемы. Я получаю lambda-expression in unevaluated context ошибку для следующего кода:
struct A {int x; int y;};
typedef decltype ([](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
}) Comp;
std::set <A, Comp > SetOfA;
Я пометил это как c ++ 0x. Это кажется более подходящим и требует более точных ответов. JoshD 28.09.2010
@JoshD Разве это не должно быть помечено как "c ++"? 0x в конечном итоге станет новым стандартом, и я бы не хотел, чтобы люди в будущем пропустили этот вопрос, потому что они забыли, что правильным тегом был c ++ 0x, а не c ++. (Или SO собирается в какой-то момент перенести все теги c ++ 0x на c ++?) KitsuneYMG 28.09.2010
Для компараторов, используемых таким образом, вам все равно лучше использовать подход, отличный от 0x:
struct A { int x; int y; };
struct cmp_by_x {
bool operator()(A const &a, A const &b) {
return a.x < b.x;
}
};
std::set<A, cmp_by_x> set_of_a;
Однако в 0x вы можете сделать cmp_by_x локальным типом (т.е. определить его внутри функции), когда это более удобно, что запрещено текущим C ++.
Кроме того, ваше сравнение рассматривает A (x = 1, y = 1) и A (x = 1, y = 2) как эквивалентные. Если это нежелательно, вам нужно включить другие значения, которые способствуют уникальности:
Не уверен, что это то, о чем вы спрашиваете, но сигнатура лямбды, которая возвращает RetType и принимает InType, будет:
std::function<RetType(InType)>
(Убедитесь, что #include <functional>)
Вы можете сократить это, используя typedef, но я не уверен, что вы можете использовать decltype, чтобы не выяснять фактический тип (поскольку лямбды, очевидно, не могут использоваться в этом контексте).
Итак, ваш typedef должен быть:
typedef std::function<bool(const A &lhs, const A &rhs)> Comp
or
using Comp = std::function<bool(const A &lhs, const A &rhs)>;
Ответ 4 · yaron kahanovitch
проблема в том, что последний параметр шаблона - это тип, а не объект, поэтому вы можете сделать следующее
std::set <A, std::fuction<bool(const A &,const A &)>>
SetOfA([](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
} > SetOfA;
для упрощения можно сделать следующее:
auto func = SetOfA([](const A lhs, const A &rhs) ->bool { return lhs.x < rhs.x;}
set <A,decltype(func)> SetOfA(func);