2012-10-29 1 views
2

Je fournis une bibliothèque qui supporte une barre de fonction(). Ce qu'il fait quand vous passez une valeur scalaire (comme un double, int, peu importe) est différent de ce qui se passe si vous transmettez quelque chose qui n'est pas une valeur scalaire (dans tous les cas prévus, un type défini par l'utilisateur). Donc, j'ai écrit le code comme ceci:Modèle pour non-builtins, surcharge pour builtins

#include <iostream> 

class Foo 
{ 
public: 
    template <class T> void bar(T const &rhs) { std::cout << "T" << std::endl; } 
    void bar(double rhs) { std::cout << "double" << std::endl; } 
}; 

int main() 
{ 
    Foo foo; 
    foo.bar(4); 
} 

Le problème avec ceci est sur la deuxième ligne de main(). Le résultat de ce code est la sortie de "T". Le compilateur préfère le template sur l'appel à bar (double), et je suppose que c'est parce que le paramètre est un int, qu'il préfèrerait convertir en int const & (puisque un const & peut faire référence à une valeur r).

Ma question est "est-il possible de supporter chaque valeur scalaire sans les appeler explicitement?" Je ne veux vraiment pas appeler tous les types possibles, parce que ... eh bien ... il y en a beaucoup. Je devrais couvrir tout de char à longtemps long, inclure chaque combinaison de volatile et non signé, et ainsi de suite.

Je sais que le simple fait de changer le 4 à un 4.0 fonctionne, mais c'est pour l'interface publique à une bibliothèque, et demandant à l'utilisateur de taper 4.0 au lieu de 4 est juste sale.

+1

Voulez-vous vraiment tous les types de scalaires, y compris les types de pointeurs? Sinon, le mot que vous recherchez est * arithmétique * types. – Xeo

+0

Bon point, je veux juste juste des types arithmétiques selon la définition de C++; mon terme «scalaire» a plus de sens dans le contexte de la bibliothèque sur laquelle je travaille. – Shirik

Répondre

4

Oui, avec des traits:

#include <type_traits> 
#include <iostream> 

class Foo 
{ 
public: 
    template <class T> 
    typename std::enable_if<!std::is_scalar<T>::value, void>::type bar(T const & rhs) 
    { 
     std::cout << "T" << std::endl; 
    } 

    void bar(double rhs) 
    { 
     std::cout << "double" << std::endl; 
    } 
}; 

Il y a six catégories de base de types: fonctions, scalaires, des tableaux, des classes, des syndicats et des références. Et void. Chacun d'eux a un trait correspondant. See here for more details.

+0

Ceci est une excellente réponse, et une partie de la raison pour laquelle j'aime C++ 11. Malheureusement, le compilateur que j'utilise pour ce projet ne supporte pas C++ 11 (et la mise à jour n'est pas une option). Il semble que boost ait un is_scalar, donc je vais voir si ça va marcher. – Shirik

+0

Je pense qu'un trait personnalisé basé sur 'is_arithmetic' et' is_enum' serait plus approprié ici. Ou peut-être même simplement 'is_arithmetic'. – Xeo

+0

Vous pouvez regarder le ["implémentation possible"] (http://en.cppreference.com/w/cpp/types/is_scalar) dans le manuel, mais certains de ces traits requièrent le support du compilateur, j'en ai peur. –

Questions connexes