双模板方法的部分专门化失败 [英] Partial specialization of double-templated method fails

查看:199
本文介绍了双模板方法的部分专门化失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有模板类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的方法负载?此代码无效...

How to specialize method load for N=2? This code is not valid...

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


推荐答案

事实证明,C ++规范中有一个规定,明确禁止专门化模板类或函数嵌套在模板类内部,除非你也明确专门化外部模板。 Visual Studio不强制执行此规则,因此与前面的示例混淆,但是g ++肯定会出现。

It turns out that there's a provision in the C++ spec that explicitly disallows specializing a template class or function nested inside of a template class unless you also explicitly specialize the outer template as well. Visual Studio doesn't enforce this rule, hence the confusion with the previous example, but g++ certainly does.

如果你想特殊化模板,你的选项将是还专门化外部模板或以某种方式通过使方法基于模板参数分派到两个不同实现中的一个来伪造特化的行为。这些都不是非常令人满意,我知道,但不幸的是,语言设计奇怪的一些模板角。 : - (

If you want to specialize the template, your options will either be to also specialize the outer template or to somehow fake up the behavior of specialization by having the method dispatch to one of two different implementations based on the template parameter. Neither of these are very satisfying, I know, but unfortunately the language is designed weirdly in some template corners. :-(

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

One way that you can emulate the behavior of the explicit specialization is to use a technique called tag dispatching. The idea is that we'll make a very simple struct that looks like this:

template <unsigned short N> struct Box {};

这种类型是完全空的,它不是直接使用,而只是嵌入特别是 Box< 3> 不是与 Box <4>相同的类型 ,等等。

This type is completely empty. It's not meant to be used directly, but rather is just a way of embedding an integer into the type system. In particular, Box<3> is not the same type as Box<4>, etc.

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

Next, in your list class, define two functions that look like this, preferably marked private:

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

这两个函数是彼此重载的,只能通过它们的最终参数是在模板情况下的 Box 或在非模板情况下的 Box <2> 。请注意,这些参数没有名称。这是一个随意的决定,但由于我们不打算实际读取参数,我们不需要它们。这些函数的直觉是,这个第一个函数将是catch-all实现,它将为除了2之外的任何 N 工作。第二个版本将包含加载 N == 2

These two functions are overloads of one another, distinguishable only by their final parameter, which is either a Box<N> in the template case or a Box<2> in the non-template case. Note that the parameters don't have names. This is an arbitrary decision, but since we're not planning on actually reading the parameters, we don't need them. The intuition behind these functions is that this first function will be the "catch-all" implementation that will work for any N except 2. The second version will contain the implementation of loading for the case where 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 的模板版本的调用,这是catch-all处理程序。如果,另一方面, N 是两个,那么这将调用 doLoad 的非模板版本,因为非模板函数在重载解析过程中优先于模板函数。

How does this work? This function takes in a parameter, and then calls doLoad forwarding that parameter as the first argument and passing a temporary Box<N> as the second argument. If N is not two, then this is a call to the template version of doLoad, which is the catch-all handler. If, on the other hand, N is two, then this will call the non-template version of doLoad, because non-template functions have priority over template functions during overload resolution.

总之, load 一个蹦床把你转向正确的两个实现。然后可以将逻辑放在相应的 doLoad 函数中,以获得所需的行为。

In short, the implementation of load just becomes a trampoline to forward you to the correct of the two implementations. You can then put the logic in the appropriate doLoad function to get the behavior you want.

希望这有助于!

这篇关于双模板方法的部分专门化失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆