双模板方法的部分特化失败

Rob*_*obo 7 c++ templates partial-specialization specialization

有模板类List.

template <typename Point>
class List
{


    public:
          template <const unsigned short N>
          void load ( const char *file);
          ...
};

template <typename Point>
template <const unsigned short N>
void List <Point>::load ( const char *file)
}
Run Code Online (Sandbox Code Playgroud)

如何专门化N = 2的方法负载?此代码无效...

template <typename Point>
void List <Point> <2>::load ( const char *file)
{
}
Run Code Online (Sandbox Code Playgroud)

而且这段代码也行不通.

template <typename Point>
void List <Point> ::load <2> ( const char *file )
{ 
}

Error 3 error C2768: 'List<Point>::load' : illegal use of explicit template arguments 66. 
Error 5 error C2244: 'List<Point>::load' : unable to match function definition to an existing declaration 66
Run Code Online (Sandbox Code Playgroud)

编译器g ++:

template <typename Point>
template <>
void List <Point> ::load <2> ( const char *file )
{
}

error: explicit specialization in non-namespace scope `class List<>'
error: enclosing class templates are not explicitly specialized
error: default arguments are only permitted for function parameters
error: `load' is not a function template
error: invalid function declaration
Run Code Online (Sandbox Code Playgroud)

tem*_*def 8

事实证明,C++规范中有一个规定明确禁止专门化嵌套在模板类中的模板类或函数,除非您也明确地专门化外部模板.Visual Studio不强制执行此规则,因此与前面的示例混淆,但g ++当然可以.

如果你想专门化模板,你的选择将是专门化外部模板或通过让方法根据模板参数调度到两个不同的实现之一来某种方式伪造特化的行为.我知道,这些都不是非常令人满意,但遗憾的是,这些语言在某些模板角落设计得非常奇怪.:-(

可以模拟显式特化的行为的一种方法是使用称为标签分派的技术.我们的想法是,我们将创建一个非常简单的结构,如下所示:

template <unsigned short N> struct Box {};
Run Code Online (Sandbox Code Playgroud)

这种类型完全是空的.它并不意味着直接使用,而只是一种将整数嵌入到类型系统中的方法.特别Box<3>是,与... Box<4>等的类型不同

接下来,在列表类中,定义两个看起来像这样的函数,最好标记为private:

template <unsigned short N>
    void doLoad(const char* file, Box<N>);
void doLoad(const char* file, Box<2>);
Run Code Online (Sandbox Code Playgroud)

这两个函数是彼此的重载,只能通过它们的最终参数来区分,最终参数可以是Box<N>模板情况下的Box<2>,也可以是非模板情况下的参数.请注意,参数没有名称.这是一个随意的决定,但由于我们没有计划实际读取参数,我们不需要它们.这些函数背后的直觉是,第一个函数将是"catch-all"实现,它将适用于N除2之外的任何实现.第二个版本将包含用于案例的加载实现N == 2.

最后,实现load如下:

template <typename Point>
    template <unsigned short N>
void List<Point>::load(const char* file) {
    doLoad(file, Box<N>());
}
Run Code Online (Sandbox Code Playgroud)

这是如何运作的?此函数接受一个参数,然后调用doLoad转发该参数作为第一个参数,并将临时值Box<N>作为第二个参数传递.如果N不是两个,那么这是对模板版本的调用doLoad,这是catch-all处理程序.另一方面,如果N是2,那么这将调用非模板版本doLoad,因为非模板函数在重载解析期间优先于模板函数.

简而言之,实现load只是成为一个蹦床,将你转发到两个实现的正确.然后,您可以将逻辑放在适当的doLoad函数中以获得所需的行为.

希望这可以帮助!