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

发布于 2024-10-16 21:06:26 字数 1290 浏览 5 评论 0原文

有模板类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

There is the template class 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)
}

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

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

And this code also does not work.

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

Compiler 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

西瑶 2024-10-23 21:06:26

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

如果您想专门化模板,您的选择要么是也专门化外部模板,要么以某种方式通过根据模板参数将方法分派到两个不同实现之一来伪造专门化的行为。我知道,这些都不是很令人满意,但不幸的是,该语言在某些模板角落设计得很奇怪。 :-(

模拟显式专业化行为的一种方法是使用一种称为标记分派的技术。这个想法是我们将创建一个非常简单的结构,如下所示

template <unsigned short N> struct Box {};

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

接下来,在列表类中,定义两个如下所示的函数,最好标记为私有:

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

这两个函数是彼此的重载,只能通过它们的最终参数来区分,该参数可以是模板情况下的 Box 或非模板情况下的 Box<2> 请注意,参数没有名称。 ,但由于我们不打算实际读取参数,因此我们不需要它们。这些函数背后的直觉是,第一个函数将是适用于任何 N< 的“包罗万象”的实现。 /code> 除 2 之外。第二个版本将包含 N == 2 情况下的加载实现。

最后,按如下方式实现 load

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

这是如何工作的?该函数接受一个参数,然后调用 doLoad 将该参数作为第一个参数转发,并传递一个临时 Box 作为第二个参数。如果 N 不是 2,则这是对 doLoad 模板版本的调用,它是包罗万象的处理程序。另一方面,如果 N 为 2,则这将调用 doLoad 的非模板版本,因为在重载解析期间非模板函数比模板函数具有优先级。

简而言之,load 的实现只是变成了一个蹦床,将您转发到两个实现中正确的一个。然后,您可以将逻辑放入适当的 doLoad 函数中以获得您想要的行为。

希望这有帮助!

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

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.

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>);

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.

Finally, implement load as follows:

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

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.

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.

Hope this helps!

删除→记忆 2024-10-23 21:06:26

编辑
好的,所以我用内联函数定义稍微重写了你的类,这绝对有效:

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

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

Edit:
Ok, so I rewrote your class a bit, with inlined function definitions, and this definitely works:

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

    template<>
    void load<2>(const char* file){
    }
};
情绪 2024-10-23 21:06:26

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

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

You cannot specialize a member template without also specializing the class template.

I also wonder what the meaning of N could be, as it is not used in the function parameter?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文