2016-01-25 10 views
8

Wenn eine Vorlage vollständig spezialisiert ist, muss eine Elementfunktion nicht dupliziert werden. Im folgenden Code wird beispielsweise foo() nur einmal geschrieben.Vorlage teilweise Spezialisierung: Wie kann Codeduplizierung vermieden werden?

#include <iostream> 

template<int M> 
class B 
{    
public: 
    void foo(); 
private: 
    void header(); 
};   

template<int M> 
void   
B<M>::foo() 
{ 
    // specialized code:    
    header(); 
    // generic code: 
    std::cout << "M = " << M << std::endl;    
}     

template<int M>                
void                   
B<M>::header()                
{                   
    std::cout << "general foo()" << std::endl;        
}                   

template<>                 
void                   
B<2>::header()                
{                   
    std::cout << "special foo()" << std::endl; 
} 

jedoch für die partielle Spezialisierung ist es erforderlich, die Klassendefinition und alle Member-Funktionen zu duplizieren. Zum Beispiel:

#include <iostream> 

template<int M, int N> 
class A 
{     
public: 
    void foo(); 
private: 
    void header(); 
};  

template<int M, int N> 
void    
A<M, N>::foo() 
{   
    // specialized code: 
    header(); 
    // generic code: 
    std::cout << "M = " << M << ", N = " << N << std::endl; 
}          

template<int M, int N> 
void             
A<M, N>::header() 
{                   
    std::cout << "general foo()" << std::endl;        
}                   

template<int N>                
class A<2, N>                
{                   
public:                  
    void foo();                
private:                  
    void header();               
};                   

template<int N>                
void                   
A<2, N>::foo()                
{                   
    // specialized code:              
    header();                
    // generic code:               
    std::cout << "M = " << 2 << ", N = " << N << std::endl;     
}                   

template<int N> 
void                   
A<2, N>::header()               
{                   
    std::cout << "special foo()" << std::endl;        
} 

Hinweis, dass ein Duplikat A<2, N>::foo()A<M, N>::foo() mit 2 manuell für M substituiert ist.

Wie kann eine solche Codeverdopplung in diesem Kontext der Template-Teilspezialisierung vermieden werden?

+0

Ich hatte keine Ahnung, Sie ohne Spezialisierung die ganze Klasse eine Methode für eine Klasse-Vorlage spezialisieren können. – bolov

+1

In Verbindung stehend: http://stackoverflow.com/q/25119444/951890 –

Antwort

1

Sie header in eine separate Klasse bewegen konnte und nur teilweise mit Spezialisierung dieses:

#include <iostream> 

template <int M, int N> 
struct Header 
{ 
    static void header() 
    { 
     std::cout << "general foo()" << std::endl; 
    } 
}; 

template <int N> 
struct Header<2, N> 
{ 
    static void header() 
    { 
     std::cout << "special foo()" << std::endl; 
    } 
}; 

template<int M, int N> 
struct A 
{     
    void foo(); 
};  

template<int M, int N> 
void    
A<M, N>::foo() 
{   
    Header<M,N>::header(); 
    std::cout << "M = " << M << ", N = " << N << std::endl; 
} 

int main() 
{ 
    A<1,1> a11; 
    a11.foo(); 

    A<2,5> a25; 
    a25.foo(); 
} 

Ausgang

general foo() 
M = 1, N = 1 

special foo() 
M = 2, N = 5 

live example

2

In diesem Fall würde ich eine Basis machen Klasse, die den Vorlagenparameter 'N' nicht kennt:

#include <iostream> 

template<int M> 
class ABase 
{ 
protected: 
    void header(); 
}; 

template<int M> 
void 
ABase<M>::header() 
{ 
    std::cout << "general header()" << std::endl; 
} 


template<> 
void ABase<2>::header() 
{ 
    std::cout << "special header()" << std::endl; 
} 

template<int M, int N> 
class A : private ABase<M> 
{ 
public: 
    void foo(); 
}; 

template<int M, int N> 
void 
A<M, N>::foo() 
{ 
    // specialized code: 
    this->header(); 
    // generic code: 
    std::cout << "M = " << M << ", N = " << N << std::endl; 
} 

int main() 
{ 
    A<1,0> a1; 
    a1.foo(); 

    A<2,0> a2; 
    a2.foo(); 
} 

Alternativ könnten Sie die gesamte Basisklasse spezialisieren.

1

obligatorische Antwort mit Tag-Versand:

Sie können eine überladene Hilfsfunktion erstellen; eines, das im M == 2 Fall aufgerufen wird, und das andere, wenn M != 2. Auf diese Weise können Sie das Erstellen einer Vorlagenbasisklasse vermeiden. Alles, was wir ist drehen Sie den Zustand M == 2 in eine Art tun müssen, was wir std::true_type und std::false_type verwenden <type_traits>

template<int M, int N> 
class A 
{     
public: 
    void foo(); 
private: 
    void header(); 
    void foo_helper(std::true_type); // for M == 2 case 
    void foo_helper(std::false_type); // for M != 2 case 
}; 

Übersetzung in eine Art auszuführen (Zeit kompilieren-check) tun wird:

template<int I> 
struct is_2 : std::false_type{}; 

template<> 
struct is_2<2> : std::true_type{}; 

Und Sie können sie wie so nennen:

template<int M, int N>                
void                   
A<M, N>::foo()                
{  
    foo_helper(typename is_2<M>::type{}); 
    // specialized code:              
    header();                
    // generic code:               
    std::cout << "M = " << M << ", N = " << N << std::endl;     
} 

template<int M, int N>                
void                   
A<M, N>::foo_helper(std::true_type) 
{ 
    std::cout << "Specialized code for M==2 case\n"; 
} 

template<int M, int N>                
void 
A<M,N>::foo_helper(std::false_type) 
{ 
    std::cout << "M!=2 case\n"; 
} 

Demo


Wenn Sie vermeiden möchten, benötigen ein Konzept zu erstellen, dann können Sie überlasten stattdessen auf std::integral_constant, aber Sie werden einige Kompilierung-Vorlage aufblasen (See Jarod42's answer here) erhalten:

// inside void foo() 
foo_helper(std::integral_constant<int, M>()); 


template<typename T> 
void foo_helper(T) // for M != 2 case 
{ 
    std::cout << "M!=2 case\n"; 
} 


void foo_helper(std::integral_constant<int, 2>) // for M == 2 case 
{ 
    std::cout << "Specialized code for M==2 case\n"; 
} 

Demo 2

0

Danke an alle, die Antworten gegeben haben.

Nach dem Link von Vaughn Cato und weiter entlang einem anderen Link führt zu this Lösung, die std::enable_if eher als Vorlage teilweise Spezialisierung verwendet.

es für das Problem bei der Hand Implementierung gibt:

#include <iostream> 

template<int M, int N> 
class A 
{ 
public: 
    void foo(); 

private: 
    template<int MM = M, int NN = N, 
      typename std::enable_if<MM != 2>::type* = nullptr> 
    void header() 
    { 
     std::cout << "general foo()" << std::endl; 
    } 

    template<int MM = M, int NN = N, 
      typename std::enable_if<MM == 2>::type* = nullptr> 
    void header() 
    { 
     std::cout << "special foo()" << std::endl; 
    } 
}; 

template<int M, int N> 
void 
A<M, N>::foo() 
{ 
    // specialized code: 
    header(); 
    // generic code: 
    std::cout << "M = " << M << ", N = " << N << std::endl; 
} 
Verwandte Themen