Como posso escrever um modelo de função para todos os tipos com uma característica de tipo específico?

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

  •  22-09-2019
  •  | 
  •  

Pergunta

Considere o seguinte exemplo:

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

o Scanner A classe é usada para extrair tokens de alguma fonte. O código acima funciona bem, mas falha quando tento get outros tipos integrais, como um char ou um unsigned int. O código para ler esses tipos é exatamente o mesmo que o código para ler um int. Eu poderia apenas duplicar o código para todos os outros tipos integrais que gostaria de ler, mas prefiro definir um modelo de função para todos os tipos integrais.

Eu tentei o seguinte:

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

O que funciona como um charme, mas não tenho certeza de como conseguir Scanner::get<string>() para funcionar novamente. Então, como posso escrever código para que eu possa fazer scanner.get<string>() e scanner.get<any integral type>() E tem uma única definição para ler todos os tipos integrais?

ATUALIZAÇÃO: Pergunta de bônus: E se eu quiser aceitar mais de uma variedade de classes com base em algumas características? Por exemplo: como devo abordar esse problema se quiser ter três get funções que aceitam (i) tipos integrais (ii) tipos de pontos flutuantes (iii) strings, respectivamente.

Foi útil?

Solução

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

Atualize "E se eu quiser aceitar mais de uma variedade de classes com base em algumas características?"

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

Outras dicas

Adiar para outro modelo. Aqui está o padrão geral para o que você deseja:

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top