模板部分专业化:如何避免代码重复?

时间:2016-01-25 17:21:38

标签: c++ templates partial-specialization

当模板完全专用时,不需要复制成员函数。例如,在以下代码中,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

在模板部分专业化的上下文中如何避免此类代码重复?

4 个答案:

答案 0 :(得分:2)

在这种情况下,我会让基类不知道模板参数&#39; N&#39;:

#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 :(得分: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 :(得分: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

答案 3 :(得分:0)

感谢所有提供答案的人。

按照Vaughn Cato提供的链接并继续沿另一个链接转到this解决方案,该解决方案使用class C end p C.instance_methods #=> [:module_meth, :nil?, :===, :=~, :!~,... p Hash.instance_methods.grep(/module_meth/) #=> [:module_meth] p [].module_meth #=> "module meth" 而非模板部分专精化。

为手头的问题实施它会产生:

std::enable_if