Pregunta

He estado jugando con functors en C ++. En particular, tengo un vector de pares que me gustaría ordenar por el primer elemento del par. Comencé a escribir un functor completamente especializado (es decir, algo así como '' bool MyLessThan (MyPair & amp; lhs, MyPair & amp; rhs) ''). Entonces, solo porque este tipo de cosas es interesante, quería intentar escribir un " Aplicar F genérico a los primeros elementos de este par " Functor Escribí lo siguiente, pero a g ++ no le gusta. Obtengo:

error: falta de coincidencia de tipo / valor en el argumento 2 en la lista de parámetros de plantilla para 'template struct Pair1stFunc2' error: esperaba un tipo, obtuve 'menos'

#include <algorithm>
#include <functional>
#include <utility>
#include <vector>

template <class P, class F>
struct Pair1stFunc2
{
    typename F::result_type operator()(P &lhs, P &rhs) const
    { return F(lhs.first, rhs.first); }

    typename F::result_type operator()(const P &lhs, const P &rhs) const
    { return F(lhs.first, rhs.first); }
};

typedef std::pair<int,int> MyPair;
typedef std::vector<MyPair> MyPairList;

MyPairList pairs;

void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<MyPair, std::less>());
}

¿Alguien puede arrojar alguna luz sobre lo que estoy haciendo mal aquí? Sé que este es un ejemplo ligeramente artificial, pero me gustaría saber qué está pasando, aunque solo sea para mejorar mi STL-fu.

¿Fue útil?

Solución

Debe especializar std :: less con el tipo de comparación que está utilizando.

Pair1stFunc2<MyPair, std::less<int> >()

hará el truco. Dentro de su propio operador () también necesitará crear una instancia de un objeto del tipo de comparación, ya que no puede llamar directamente a la clase. P.ej. cambio

return F(lhs.first, rhs.first);

a

F func;
return func(lhs.first, rhs.first);

También puedes mover la especialización al functor, como sugiere otra respuesta.

Otros consejos

Para ampliar la respuesta de dirkgently, aquí hay un ejemplo de lo que podría funcionar como usted pretende:

template <typename T, template <typename> class F>
struct Pair1stFunc2
{
    template <typename P>
    typename F<T>::result_type operator()(P &lhs, P &rhs) const
    { F<T> f; return f(lhs.first, rhs.first); }

    template <typename P>
    typename F<T>::result_type operator()(const P &lhs, const P &rhs) const
    { F<T> f; return f(lhs.first, rhs.first); }
};

void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<int, std::less>());
}

Tenga en cuenta que funciona, pero puede que no sea exactamente lo que tenía en mente.

Tenga en cuenta que std :: less es en sí mismo una plantilla y no especifica el parámetro de la plantilla de plantilla cuando lo llama con la ordenación de la función foo () ! Aquí less es un tipo incompleto y de ahí el problema.

Similar a unfesen. Pero no es necesario utilizar plantillas de plantillas.

#include <algorithm>
#include <functional>
#include <memory>
#include <vector>

typedef std::pair<int,int> MyPair;
typedef std::vector<MyPair> MyPairList;
MyPairList pairs;


// Same as original.
template <typename T,typename F>
struct Pair1stFunc2
{
    template <typename P>
    typename F::result_type operator()(P &lhs, P &rhs) const
    { F f;  // Just need to create an anstance of the functor to use.
      return f(lhs.first, rhs.first); }

    template <typename P>
    typename F::result_type operator()(const P &lhs, const P &rhs) const
    { F f;  // Just need to create an anstance of the functor to use.
      return f(lhs.first, rhs.first); }
};


void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<int, std::less<int> >()); // initialize the version of less
}

La solución más sencilla sería indicar lo que quiere como un argumento, una función con una firma adecuada:

template<typename P, bool (*F)(P,P)> struct Pair1stFunc2 { ... }

En este caso, pasar una plantilla de función como segundo argumento provocará que se realice una resolución de sobrecarga con P, P como tipos de argumento. Esto funciona porque mueve la resolución de sobrecarga de struct Pair1stFunc2 :: operator ()

También desea la posibilidad de pasar un functor , pero estos deben pasarse como un argumento de tipo de plantilla y luego crearse dentro del operador ():

typename F::result_type operator()(const P &lhs, const P &rhs) const
{ return F()(lhs.first, rhs.first); }

Aquí, F es el tipo de functor y F () una instancia de ese funtor.

El tercer caso ya está cubierto anteriormente, la plantilla functor. std :: less es una plantilla de este tipo. En ese caso, necesita un argumento de plantilla de plantilla.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top