2009-05-26 4 views
3

J'ai besoin d'un template C++ qui, donné un type et un objet de ce type, peut prendre une décision selon que le type est un entier ou pas, tout en pouvant accéder aux objets réels. J'ai essayé ceciProblème de spécialisation de template C++

template <typename T, T &N> 
struct C { 
    enum { Value = 0 }; 
}; 

template <int &N> 
struct C<int, N> { 
    enum { Value = N }; 
}; 

mais cela ne fonctionne pas. Y a-t-il un moyen de réaliser quelque chose de similaire?

Modifier

Ce que je cherchais à atteindre était quelque chose comme ça, que se passerait-il au moment de la compilation:

if (type is int) { 
    return IntWrapper<int_value> 
else { 
    return type 
} 

Vous pouvez passer en fait des pointeurs ou des références à des objets dans un instanciation de modèle, comme si:

struct X { 
    static const int Value = 5; 
}; 

template <X *x> 
struct C { 
    static const int Value = (*x).Value; 
}; 

X x; 

std::cout << C<&x>::Value << std::endl; // prints 5 

mais apparemment tout cela accomplit est d'initialiser le modèle par infer Le type x et le x doivent également être déclarés globalement. Pas d'utilité pour ce que j'essaie de faire, ce que je pense n'est pas possible après tout au moment de la compilation.

+0

Il semble que vous ayez besoin d'un modèle de fonction, car les modèles de classe requièrent que vous spécifiiez explicitement les arguments de type de modèle. Pourriez-vous poster un exemple d'utilisation pour clarifier ce que vous essayez de faire? –

+0

@j_random_hacker: Vous pouvez laisser le modèle vierge et avoir une classe spécialisée ... vous n'avez pas besoin de spécifier un type de modèle. – Partial

Répondre

7

Ce que vous essayez de faire n'est pas un modèle C++ valide. Vous ne pouvez pas utiliser des objets arbitraires comme paramètres de modèle, tout ce que vous pouvez utiliser sont des types, des littéraux entiers et dans certains cas spécialisés des littéraux de chaîne.

+0

Et les valeurs booléennes aussi –

+0

Je ne sais pas pourquoi quelqu'un vous a downvoted, mais j'espère que d'autres vous aideront à vous sur le dessus ... – Pieter

3

template <typename T> struct A 
{ 
    enum { Value = false }; 
}; 
template <> struct A<int> 
{ 
    enum { Value = true }; 
}; 

Qu'en est-ce alors:


template <typename T> struct A 
{ 
    T value_; 
    A() : value() {} 
    enum { is_int = false }; 
}; 
template <> struct A<int> 
{ 
    int value_; 
    explicit A(int v) : value_(v) {} 
    enum { is_int = true }; 
}; 
+0

Cela fonctionnerait, mais j'ai également besoin de la valeur réelle si c'est un nombre entier. – drill3r

2

Vous pouvez le faire comme ceci:

template<typename T, int val> 
struct Test 
{ 
    enum {Value = 0}; 
}; 

template <int val> 
struct Test<int, val> 
{ 
    enum {Value = val}; 
}; 




int main(int argc,char *argv[]) 
{ 
    int v = Test<int,1>::Value; 
} 
3

addition aux autres postes: Vous n'avez pas besoin d'utiliser le enum {} -hack plus:

template<typename T, int val> 
struct Test { 
    static const int Value = 0; 
}; 

template <int val> 
struct Test<int, val> { 
    static const int Value = val; 
}; 


int main(int argc,char *argv[]) { 
    const int v = Test<int,1>::Value; 
} 
0

simple solution à vous code r - lâche la référence:

template <typename T, T N> 
struct C { 
    enum { Value = 0 }; 
}; 

template <int N> 
struct C<int, N> { 
    enum { Value = N }; 
}; 

à l'aide de référence dans un argument de modèle n'a pas de sens de toute façon parce que vous n'êtes pas vraiment passer l'argument nulle part.

+1

Ce joli fonctionne seulement avec des nombres entiers. Essayez-le avec le flotteur. –

4

Peut-être qu'une simple méthode de modèle surchargé fonctionne dans votre cas?

template<typename T> 
void doSomething(const T& x) 
{ 
    // ... 
} 
void doSomething(int x) 
{ 
    // ... 
} 
2

je besoin d'un C++ modèle qui, étant donné un type et un objet de ce type, il peut prendre une décision selon que le type est un nombre entier ou non, tout en pouvoir accéder aux objets réels .

Vous pouvez prendre des décisions basées sur le type étant un nombre entier ou non, le problème est qu'il est impossible de déclarer un modèle avec un objet de n'importe quel type. Donc, la question sur la façon de décider si un type est un nombre entier est discutable.

Notez que dans toutes les réponses de votre modèle d'origine est soigneusement changé

template < typename T, int > 
class C {}; 

au lieu de votre

template< typename T, T > 
class C {}; 

Mais alors que C<int, 5> est une déclaration parfaitement valable, ce n'est pas le cas pour un arbitraire type T, le cas au point C<float, 5.> donnera une erreur de compilation.

Pouvez-vous poster ce que vous essayez d'atteindre exactement?

Et pour mémoire, si le second argument de modèle est toujours un int, et que vous voulez simplement prendre sa valeur si le type est un type entier, et 0 otherwhise, vous pouvez simplement faire:

#include <limits> 

template< typename T, int N > 
class C { 
    static const int Value = (std::numeric_limits<T>::is_integer) ? N : 0; 
}; 
0

Découvrez les Modern C++ Design d'Alexandrescu. Je crois que le chapitre 2 a un bon exemple de ce que vous voulez faire.

5

À moins que je ne vous comprenne mal, ce que vous voulez est impossible. Dans votre exemple, vous montrez une utilisation incorrecte d'un paramètre de modèle de pointeur.

template <X *x> 
struct C { 
    static const int Value = (*x).Value; 
}; 

Ce n'est pas valable, puisque (*x).Value doit être une expression constante pour qu'il soit en mesure d'initialiser Value. Sûr Value dans la classe X serait bien comme une expression constante lorsqu'il est utilisé comme X::Value à la place. Mais cette fois, ce n'est pas parce qu'il s'agit d'un pointeur (les références sont également invalides dans les expressions constantes).

Pour résumer, vous ne pouvez pas le faire:

Magic<T, someT>::type 

Et attendez ::type être T si T est pas int, et IntWrapper<someT> autrement, puisque T ne peut être une énumération, entier, pointeur ou type de référence. Et dans les deux derniers cas, vous n'obtiendrez pas à la "valeur" de tout point pointé par le pointeur ou référencé par la référence à temps de compilation. Si vous êtes satisfait de cela, il est facile de résoudre votre problème et je ne vais pas vous montrer comment (je suppose que vous savez déjà comment).

Je pense que vous vous êtes retrouvé dans une situation où la résolution de votre problème est devenue impossible à faire avec les règles comme indiqué. Revenez en arrière quelques étapes et montrez-nous le problème réel que vous essayez de résoudre, quand l'affaire permet encore de résoudre les choses.

0

Template specialization peut être atteint comme celui-ci (code tiré de www.cplusplus.com):

// template specialization 
#include <iostream> 
using namespace std; 

// class template: 
template <class T> 
class mycontainer { 
    T element; 
    public: 
    mycontainer (T arg) {element=arg;} 
    T increase() {return ++element;} 
}; 

// class template specialization: 
template <> 
class mycontainer <char> { 
    char element; 
    public: 
    mycontainer (char arg) {element=arg;} 
    char uppercase() 
    { 
     if ((element>='a')&&(element<='z')) 
     element+='A'-'a'; 
     return element; 
    } 
}; 

int main() { 
    mycontainer<int> myint (7); 
    mycontainer<char> mychar ('j'); 
    cout << myint.increase() << endl; 
    cout << mychar.uppercase() << endl; 
    return 0; 
} 

Dans votre cas, vous devez remplacer le charbon par ce que vous voulez dans la spécialisation de modèle de classe. Maintenant, je ne suis pas vraiment sûr de ce que vous essayez d'accomplir mais j'espère que l'exemple ci-dessus est un bon indicateur de la façon dont vous pouvez faire une spécialisation de modèle.

0

Ce que je cherchais à atteindre était quelque chose comme ça, que se passerait-il au moment de la compilation:

if (type is int) { 
    return IntWrapper<int_value> 
else { 
    return type 
} 

Je ne sais pas pourquoi vous ne l'utilisez IntWrapper pour commencer. D'où vient le besoin d'enrouler une constante entière à la compilation dans un IntWrapper, si c'est int? Dans le cas contraire, il semble que vous essayez d'instancier des modèles avec des données qui ne sont disponibles qu'au moment de l'exécution.

Questions connexes