¿Cómo puedo escribir una plantilla de función para todos los tipos con un rasgo determinado tipo?

StackOverflow https://stackoverflow.com/questions/2537229

  •  22-09-2019
  •  | 
  •  

Pregunta

Consideremos el siguiente ejemplo:

struct Scanner
{
    template <typename T>
    T get();
};

template <>
string Scanner::get()
{
    return string("string");
}

template <>
int Scanner::get()
{
    return 10;
}

int main()
{
    Scanner scanner;
    string s = scanner.get<string>();
    int i = scanner.get<int>();
}

La clase Scanner se utiliza para extraer tokens de alguna fuente. El código anterior funciona bien, pero falla cuando intento get otros tipos integrales como un char o un unsigned int. El código para leer este tipo es exactamente el mismo que el código para leer un int. Tan sólo pudiera duplicar el código para todos los demás tipos integrales que me gustaría leer, pero prefiero definir una plantilla de función para todos los tipos integrales.

He intentado lo siguiente:

struct Scanner
{
    template <typename T>
    typename enable_if<boost::is_integral<T>, T>::type get();
};

que funciona como un encanto, pero no estoy seguro cómo conseguir Scanner::get<string>() a funcionar de nuevo. Entonces, ¿cómo puedo escribir código para que yo pueda hacer scanner.get<string>() y scanner.get<any integral type>() y tienen una definición única para leer todos los tipos integrales?

Actualización: pregunta prima : ¿Qué pasa si quiero aceptar más de una variedad de clases sobre la base de algunos rasgos? Por ejemplo: ¿cómo debería abordar este problema si quiero tener tres funciones get que aceptan (i) tipos integrales (ii) los tipos de punto flotante (iii) las cuerdas, respectivamente

.
¿Fue útil?

Solución

struct Scanner
{
    template <typename T>
    typename boost::enable_if<boost::is_integral<T>, T>::type get()
    {
        return 10;
    }
    template <typename T>
    typename boost::disable_if<boost::is_integral<T>, std::string>::type get()
    {
        return "string";
    }
};

Actualizar "¿Qué pasa si quiero aceptar más de una gama de clases basadas en algunos rasgos?"

struct Scanner
{
    template <typename T>
    typename boost::enable_if<boost::is_integral<T>, T>::type get()
    {
        return 10;
    }

    template <typename T>
    typename boost::enable_if<boost::is_floating_point<T>, T>::type get()
    {
        return 11.5;
    }

    template <typename T>
    std::string get(
          typename boost::disable_if<boost::is_floating_point<T>, T>::type* = 0, 
          typename boost::disable_if<boost::is_integral<T>, T>::type* = 0)

    {
        return std::string("string");
    }
};

Otros consejos

Aplazar a otra plantilla. Aquí está el patrón general de lo que quiere:

template <typename T, bool HasTrait = false>
struct scanner_impl;

template <typename T>
struct scanner_impl
{
    // Implement as though the trait is false
};

template <typename T>
struct scanner_impl<true>
{
    // Implement as though the trait is true
};

// This is the one the user uses
template <typename T>
struct scanner : scanner_impl<T, typename has_my_trait<T>::value>
{
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top