2016-01-25 3 views
8

Когда шаблон полностью специализирован, функцию-член не нужно дублировать. Например, в следующем коде foo() записывается только один раз.шаблон частичной специализации: как избежать дублирования кода?

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

Однако для частичной специализации необходимо продублировать определение класса и все функции-члены. Например:

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

Обратите внимание, что A<2, N>::foo() дубликат A<M, N>::foo() с 2 вручную заменить M.

Как можно избежать дублирования кода в этом контексте частичной специализации шаблона?

+0

Я понятия не имел, вы можете специализироваться метод шаблона класса без Специализируя весь класс. – bolov

+1

Связанные: http://stackoverflow.com/q/25119444/951890 –

ответ

1

Вы можете переместить header в отдельный класс и только частично Специализируется это:

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

выхода

general foo() 
M = 1, N = 1 

special foo() 
M = 2, N = 5 

live example

2

В этом случае я хотел бы сделать базу класс, не зная параметр шаблона '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(); 
} 

В качестве альтернативы, вы можете специализировать весь базовый класс.

1

Обязательный ответ с помощью тегов доставки:

Вы можете создать перегруженную вспомогательную функцию; тот, который вызывается в случае M == 2, а другой, когда M != 2. Это позволяет избежать создания шаблонного базового класса. Все, что нам нужно сделать, это превратить условие M == 2 в тип, который мы будем делать с помощью std::true_type и std::false_type из <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 
}; 

Для выполнения перевода в тип (время компиляции проверки):

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

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

И вы можете называть их так:

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


Если вы хотите, чтобы избежать необходимости создания концепции, то вы можете вместо этого перегрузить на std::integral_constant, но вы получите некоторый шаблон компиляции наворотов (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

Спасибо всем, кто дал ответы.

По ссылке, предоставленной Vaughn Cato и продолжающейся по другой ссылке, приводит к решению this, в котором используется std::enable_if, а не частичная специализация шаблона.

Реализация его для решаемой задачи дает:

#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; 
} 
Смежные вопросы