2016-01-25 13 views
8

Quando un modello è completamente specializzato, non è necessario duplicare una funzione membro. Ad esempio, nel seguente codice, foo() viene scritto una sola volta.: Come si può evitare la duplicazione del codice?

#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; 
} 

Tuttavia, per la specializzazione parziale, è necessario duplicare la definizione della classe e tutte le funzioni membro. Ad esempio:

#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;        
} 

noti che A<2, N>::foo() un duplicato di A<M, N>::foo() con 2 sostituito manualmente M.

Come si può evitare tale duplicazione del codice in questo contesto di specializzazione parziale del modello?

+0

Non avevo idea che è possibile specializzarsi un metodo per un modello di classe senza specializzata tutta la classe. – bolov

+1

Correlati: http://stackoverflow.com/q/25119444/951890 –

risposta

1

Si potrebbe spostare header in una classe separata e solo specializzati parziali questo:

#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(); 
} 

uscita

general foo() 
M = 1, N = 1 

special foo() 
M = 2, N = 5 

live example

2

In questo caso vorrei fare una base classe che non conosce il parametro template 'N':

#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(); 
} 

In alternativa, è possibile specializzare l'intera classe base.

1

risposta obbligatorio utilizzando tag spedizione:

è possibile creare un sovraccarico funzione di supporto; uno che viene chiamato nel caso M == 2 e l'altro quando M != 2. Questo ti permette di evitare di creare una classe base basata su modelli. Tutto quello che dobbiamo fare è trasformare la condizione M == 2 in un tipo, che faremo usando std::true_type e std::false_type da <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 
}; 

Per eseguire la traduzione in un tipo (in fase di compilazione di controllo):

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

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

E si può chiamarli in questo modo:

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


Se si vuole evitare di dover creare un concetto, allora si può invece sovraccaricare il std::integral_constant, ma si otterrà qualche modello in fase di compilazione troppo grosso (See Jarod42's answer here):

// 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

Grazie a tutti coloro che hanno fornito risposte.

Seguendo il collegamento fornito da Vaughn Cato e proseguendo lungo un altro collegamento porta alla soluzione this, che utilizza std::enable_if anziché la specializzazione parziale del modello.

Implementazione per il problema in esame dà:

#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; 
} 
Problemi correlati