Pregunta ¿Cómo usar una expresión lambda como un parámetro de plantilla?


¿Cómo usar la expresión lambda como un parámetro de plantilla? P.ej. como una clase de comparación que inicializa un std :: set.

La siguiente solución debería funcionar, ya que la expresión lambda simplemente crea una estructura anónima, que debería ser apropiada como un parámetro de plantilla. Sin embargo, se generan muchos errores.

Ejemplo de código:

struct A {int x; int y;};
std::set <A, [](const A lhs, const A &rhs) ->bool {
    return lhs.x < rhs.x;
    } > SetOfA;

Salida de error (estoy usando el compilador g ++ 4.5.1 y --std = indicador de compilación 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

¿Es ese el comportamiento esperado o un error en GCC?

EDITAR

Como alguien señaló, estoy usando expresiones lambda incorrectamente ya que devuelven un ejemplo de la estructura anónima a la que se refieren.

Sin embargo, corregir ese error no resuelve el problema. yo obtengo lambda-expression in unevaluated context error para el siguiente código:

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;

32
2017-09-28 07:24


origen


Respuestas:


El segundo parámetro de plantilla de std::set espera un tipo, no un expresión, entonces solo lo estás usando incorrectamente.

Podrías crear el conjunto así:

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

33
2017-09-28 07:39



Para los comparadores usados ​​de esta manera, aún está mejor con un enfoque que no sea 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;

Sin embargo, en 0x puede hacer de cmp_by_x un tipo local (es decir, definirlo dentro de una función) cuando sea más conveniente, lo que está prohibido por el C ++ actual.

Además, su comparación trata A (x = 1, y = 1) y A (x = 1, y = 2) como equivalentes. Si eso no se desea, debe incluir los otros valores que contribuyen a la singularidad:

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

4
2017-09-30 00:19



No estoy seguro de si esto es lo que está preguntando, pero la firma de un lambda que devuelve RetType y acepta InType será:

std::function<RetType(InType)>

(Asegurate que #include <functional>)

Puede acortar eso usando un typedef, pero no estoy seguro de que pueda usar decltype para evitar averiguar el tipo real (ya que lambdas aparentemente no se puede usar en ese contexto).

Entonces tu typedef debería ser:

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

o

using Comp = std::function<bool(const A &lhs, const A &rhs)>;

1
2017-09-29 13:29



el problema es que el último parámetro de plantilla es escribir, no un objeto, por lo que es posible que desee hacer lo siguiente

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

para hacerlo más simple, puedes hacer lo siguiente:

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

aclamaciones


0
2017-12-25 14:23