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

Как использовать лямбда-выражение в качестве параметра шаблона? Например. как класс сравнения, инициализирующий 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?

EDIT

Как кто-то указал, я неправильно использую лямбда-выражения, поскольку они возвращают экземпляр анонимной структуры, на которую они ссылаются.

Однако исправление этой ошибки не решает проблему. Я получаю 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;

Ответы [ 4 ]

33 голосов
/ 28 сентября 2010

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

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

auto comp = [](const A& lhs, const A& rhs) -> bool { return lhs.x < rhs.x; };
auto SetOfA = std::set <A, decltype(comp)> (comp);
4 голосов
/ 30 сентября 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) как эквивалентные.Если это нежелательно, вам нужно включить другие значения, которые способствуют уникальности:

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);
  }
};
1 голос
/ 29 сентября 2010

Не уверен, что это то, о чем вы спрашиваете, но подпись лямбды, которая возвращает RetType и принимает InType, будет:

std::function<RetType(InType)>

(убедитесь, что #include <functional>)

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

Так что вашtypedef должен быть:

typedef std::function<bool(const A &lhs, const A &rhs)> Comp

или

using Comp = std::function<bool(const A &lhs, const A &rhs)>;
0 голосов
/ 25 декабря 2014

проблема в том, что последний параметр шаблона - это тип, а не объект, поэтому вы можете сделать следующее

    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);

ура

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...