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

时间:2011-02-09 11:20:32

标签: c++ templates specialization partial-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)
}

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

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

此代码也不起作用。

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

编译器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

3 个答案:

答案 0 :(得分:8)

事实证明,C ++规范中有一条规定明确禁止将模板类或函数嵌套在模板类中,除非您也明确地专门化外部模板。 Visual Studio不强制执行此规则,因此与前一个示例混淆,但g ++肯定会这样做。

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

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

template <unsigned short N> struct Box {};

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

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

template <unsigned short N>
    void doLoad(const char* file, Box<N>);
void doLoad(const char* file, Box<2>);

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

最后,按如下方式实施load

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

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

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

希望这有帮助!

答案 1 :(得分:1)

修改: 好的,所以我用内联函数定义重写了一下你的类,这绝对有效:

template <typename Point>
class List
{
public:
    template <const unsigned short N>
    void load( const char *file){
    }

    template<>
    void load<2>(const char* file){
    }
};

答案 2 :(得分:1)

如果不专门使用类模板,则无法专门化成员模板。

我也想知道N的含义是什么,因为它没有在函数参数中使用?