Come posso scrivere una funzione di modello per tutti i tipi con un tipo particolare tratto?

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

  •  22-09-2019
  •  | 
  •  

Domanda

Si consideri il seguente esempio:

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 classe Scanner viene utilizzato per estrarre i token da qualche fonte. Il codice di cui sopra funziona bene, ma non riesce quando cerco di get altri tipi integrali come un char o un unsigned int. Il codice per leggere questi tipi è esattamente lo stesso del codice per leggere un int. Ho potuto solo duplicare il codice per tutti gli altri tipi integrali mi piacerebbe leggere, ma io preferisco definire una funzione di modello per tutti i tipi integrali.

Ho provato quanto segue:

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

che funziona come un fascino, ma non sono sicuro come ottenere Scanner::get<string>() a funzionare di nuovo. Così, come posso scrivere codice in modo che io possa fare scanner.get<string>() e scanner.get<any integral type>() e hanno una definizione unica di leggere tutti i tipi integrali?

Aggiornamento: question bonus : Cosa succede se voglio accettare più di una gamma di classi di base di alcuni tratti? Per esempio: come dovrei affrontare questo problema se voglio avere tre funzioni get che accettare (i) tipi integrali (ii) Tipi di punto (iii) le stringhe galleggianti, rispettivamente,

.
È stato utile?

Soluzione

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

Aggiorna "E se voglio accettare più di una gamma di classi di base di alcuni tratti?"

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

Altri suggerimenti

Rimanda ad un altro modello. Ecco il modello generale per ciò che si vuole:

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>
{
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top