2010-09-22 7 views
6

Hallo!Spécialisation de template unique C++ avec plusieurs paramètres de template

Je voudrais spécialiser seulement l'un des deux types de modèles. Par exemple. template <typename A, typename B> class X devrait avoir une implémentation spéciale pour une seule fonction X<float, sometype>::someFunc().

Exemple de code:

main.h:

#include <iostream> 

template <typename F, typename I> 
class B 
{ 
public: 
    void someFunc() 
    { 
     std::cout << "normal" << std::endl; 
    }; 

    void someFuncNotSpecial() 
    { 
     std::cout << "normal" << std::endl; 
    }; 
}; 

template <typename I> 
void B<float, I>::someFunc(); 

main.cpp:

#include <iostream> 
#include "main.h" 

using namespace std; 

template <typename I> 
void B<float, I>::someFunc() 
{ 
    cout << "special" << endl; 
} 

int main(int argc, char *argv[]) 
{ 
    B<int, int> b1; 
    b1.someFunc(); 
    b1.someFuncNotSpecial(); 

    B<float, int> b2; 
    b2.someFunc(); 
    b2.someFuncNotSpecial(); 
} 

Compilation échoue pour class B. Est-il vrai, que ce n'est pas possible en C++ de cette façon? Quelle serait la meilleure solution de contournement?

[modifier]

template <float, typename I> void B<float, I>::someFunc(); conduit à main.h: 26: Erreur: 'float' est pas un type valide pour un paramètre constant modèle

template <typename I> void B<float, I>::someFunc(); conduit à main.h: 27: erreur: utilisation invalide du type incomplet «classe B»

Et j'utilise gcc.

[modifier]

Je ne veux pas se spécialiser toute la classe, car il y a d'autres fonctions qui ne sont pas une spécialisation.

+0

Le modèle de classe A est-il lié à votre question? – Doug

+0

Je pensais que cela rendrait la question plus facile à comprendre. Je vais l'enlever. – tauran

+0

Cela a été demandé des centaines de fois sur stackoverflow :) Je pense que certains d'entre nous pourraient mettre en place un vrai modèle de FAQ avec de telles questions. Les gens peuvent vérifier la faq pour voir si leur question est répondue, au lieu d'avoir à chercher une dupe. –

Répondre

16

Vous devez fournir une spécialisation partielle du modèle de classe B:

template <typename I> 
class B<float, I> 
{ 
public: 
    void someFunc(); 
}; 

template <typename I> 
void B<float, I>::someFunc() 
{ 
    ... 
} 

Vous pouvez également définir simplement someFunc dans la spécialisation.

Cependant, si vous souhaitez uniquement spécialiser une fonction, et non une classe. g.

template <typename F, typename I> 
void someFunc(F f, I i) { someFuncImpl::act(f, i); } 

template <typename F, typename I> 
struct someFuncImpl { static void act(F f, I i) { ... } }; 

// Partial specialization 
template <typename I> 
struct someFuncImpl<float, I> { static void act(float f, I i) { ... } }; 

Mais vous ne pouvez pas spécialiser un modèle de fonction sans cette astuce.

+1

Vous ne pouviez pas le savoir. Mais dans mon cas d'utilisation, il y a beaucoup d'autres fonctions qui n'ont pas de spécialisation. Avec cette approche, je devrais doubler toutes ces fonctions. – tauran

+1

@tauran: Vous ne pouvez pas fournir de spécialisations partielles pour les modèles de fonction. Uniquement pour les modèles de classe, et vous devez fournir la définition à nouveau pour toute la classe. Vivre avec, ou voir la réponse mise à jour. –

+0

Pourriez-vous s'il vous plaît répondre à une autre chose dans le code de tauran? Il y a 'template void B :: someFunc();' à la fin de 'main.h'. Je pense que tauran veut déclarer, qu'il y a une spécialisation définie quelque part, dans une autre unité de compilation. Une telle chose n'exige-t-elle pas des modèles exportés? Si la spécialisation est voulue, pour être visible dans toutes les unités de compilation, "main.h" est inclus, n'est-ce pas dans l'en-tête? –

5

Although you can totally specialize member functions of a class template, you cannot _partially specialize member functions. - Andrei Alexandrescu

partielle spécialisation de classe est expliquée par les autres affiches.

Vous pouvez cependant utiliser la surcharge:

template <class T, class U> T fun(U obj); // primary template 
template <class U> void Fun<void, U>(U obj); // illegal pertial 
// specialization 
template <class T> T fun (Window obj); // legal (overloading) 

Si vous voulez aller en profondeur dans cela, vous pouvez lire sur cette question en profondeur dans « Modern C++ Design » par A. Alexandrescu.

+0

+1 pour rappeler les surcharges de template. C'est un outil que je pense rarement à utiliser, mais qui fait le travail dans certaines situations. –

0

Solution 1. déplacez toute l'implémentation vers une classe de base telle que B_Base. puis spécialise sur float pour remplacer le someFunc. comme ci-dessous

template <typename F, typename I> 
    class B : B_Base<F, I> 
    { 
    } 

    template <typename I> 
    class B<float, I> : B_Base<flat, I> 
    { 
    public: 
     void someFunc() {....} 
    }; 

Solution 2. Utilisez la surcharge de fonction, mettre float en entrée ou boost :: is_same à être envoyé.malheureusement, vous travaillez someFunc n'a pas de paramètre. il faut donc changer l'interface.