Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как использовать лямбда-выражение в качестве параметра шаблона?

Автор вопроса: 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

c++lambdatemplatesc++11

Ответы

Ответ 1 · рейтинг 33 · kennytm

Второй параметр шаблона std::set ожидает тип, а не выражение, так что вы просто используете его неправильно.

Вы можете создать такой набор:

auto comp = [](const A& lhs, const A& rhs) -> bool { return lhs.x < rhs.x; };
auto SetOfA = std::set <A, decltype(comp)> (comp);

Ответ 2 · рейтинг 4 · Community

Для компараторов, используемых таким образом, вам все равно лучше использовать подход, отличный от 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) как эквивалентные. Если это нежелательно, вам нужно включить другие значения, которые способствуют уникальности:

struct cmp_by_x {
  bool operator()(A const &a, A const &b) {
    return a.x < b.x || (a.x == b.x && a.y < b.y);
  }
};

Ответ 3 · рейтинг 1 · Ken Simon

Не уверен, что это то, о чем вы спрашиваете, но сигнатура лямбды, которая возвращает 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);

ваше здоровье

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы