2017-01-30 2 views
1

J'essaie actuellement de mettre en œuvre mon propre lecteur d'entrée standard pour un usage personnel. J'ai créé une méthode pour lire un entier à partir de l'entrée standard et faire des vérifications sur sa validité. L'idée est que je lis une chaîne à partir de l'entrée standard, que je fais plusieurs vérifications, que je convertis en int, que je fasse les dernières vérifications, que je renvoie la valeur qui a été lue. Si une erreur se produit pendant ce temps les vérifications je vais juste remplir un errorHint pour imprimer sur std::cerr et retourner std::numeric_limits<int>::min(). Je pense que l'idée est assez simple et simple à mettre en œuvre, maintenant je voulais généraliser le concept et faire le modèle de méthode, donc fondamentalement je pouvais choisir au moment de la compilation, chaque fois que je devais lire à partir de l'entrée standard quel type de nombre entier que je veux (il pourrait être int, long, long long, unsigned long et ainsi de suite mais un entier). Pour ce faire, je l'ai créé la méthode de modèle statique suivant:C++ std :: string au modèle numéro

template< 
    class T, 
    class = typename std::enable_if<std::is_integral<T>::value, T>::type 
> 
static T getIntegerTest(std::string& strErrorHint, 
         T nMinimumValue = std::numeric_limits<T>::min(), 
         T nMaximumValue = std::numeric_limits<T>::max()); 

et la mise en œuvre dans le même fichier .hpp quelques lignes ci-dessous:

template< 
    class T, 
    class> 
T InputReader::getIntegerTest(std::string& strErrorHint, 
           T nMinimumValue, 
           T nMaximumValue) 
{ 
    std::string strInputString; 
    std::cin >> strInputString; 

    // Do several checks 

    T nReturnValue = std::stoi(strInputString); /// <--- HERE!!! 

    // Do other checks on the returnValue 

    return nReturnValue; 
} 

Maintenant, le problème est, je veux convertir la chaîne que je viens de lire et que je connais est dans la plage correcte du type entier T. Comment puis-je le faire dans le bon sens?

+1

'bool succès = std :: cin >> T_instance;, puis (autre) vérification de plage ... – LogicStuff

+1

Pourquoi ne pas simplement utiliser' std :: istringstream'? –

Répondre

2

La spécialisation d'un objet fonction est un moyen très polyvalent de modifier le comportement en fonction des caractéristiques de type.

L'approche est:

  1. définissent un modèle général pour l'opération

  2. se spécialisent le modèle pour les cas d'angle

  3. appel via une fonction d'assistance

Exemple:

#include <iostream> 
#include <type_traits> 
#include <string> 


namespace detail { 
/// general case 
    template<class Integer, typename Enable = void> 
    struct convert_to_integer { 
     Integer operator()(std::string const &str) const { 
      return std::stoi(str); 
     } 
    }; 

// special cases 
    template<class Integer> 
    struct convert_to_integer<Integer, std::enable_if_t<std::is_same<long, Integer>::value> > { 
     long operator()(std::string const &str) const { 
      return std::stol(str); 
     } 
    }; 
} 

template<class T, class StringLike> 
T to_integral(StringLike&& str) 
{ 
    using type = std::decay_t<T>; 
    return detail::convert_to_integer<type>()(str); 
}; 

int main() { 

    std::string t1 = "6"; 
    const char t2[] = "7"; 

    std::cout << to_integral<int>(t1) << std::endl; 
    std::cout << to_integral<int>(t2) << std::endl; 

    // will use the specilaisation 
    std::cout << to_integral<long>(t1) << std::endl; 
    std::cout << to_integral<long>(t2) << std::endl; 

    // will use the default case 
    std::cout << to_integral<short>(t1) << std::endl; 
    std::cout << to_integral<short>(t2) << std::endl; 
} 

p.s. votre stratégie de rapport d'erreurs a besoin de travail. Suggérer de lancer un std::runtime_error.

+0

Merci pour la réponse @Richard Hodges! Très agréable! J'apprécie beaucoup! Pour l'exception pourquoi pensez-vous qu'il est préférable de lancer une exception plutôt que d'utiliser un errorHint? En particulier, je suppose que vous suggérez de créer mon propre type d'erreur et de lancer celui-ci en cas d'échec, n'est-ce pas? – Francesco

+1

@ user2271691 idéalement votre propre type d'erreur, dérivé de std :: runtime_error ou de std :: invalid_argument. –