为什么不可扣减模板参数有问题?

时间:2019-04-28 21:07:31

标签: c++11 templates c++14 metaprogramming

尝试编译这段代码会导致错误。

template <typename T>
struct MyClass;

template <typename T, std::size_t sz>
struct MyClass<T> {
    static void print() {
        std::cout << "Partially specialized" << std::endl;
    }
};
  

错误:无法通过局部专业化推导模板参数

尝试推论sz解决了这个问题。例如:

template <typename T, std::size_t sz>
struct MyClass<T[sz]> {
    static void print() {
        std::cout << "Partially specialized" << std::endl;
    }
};

我的问题是,编译器如何解释这样的程序?不允许具有第一个结构的背后的合理原因是什么?

进一步说明: 我在想,如果初始代码是可编译的,我们可以采用诸如MyClass<int, 4>::print()之类的方式使用它。

2 个答案:

答案 0 :(得分:1)

在C ++中,我们声明了模板后,可以根据需要对其进行专门化处理,例如:

template <typename T> foo;
template <typename U> foo<U*>;

现在,编译器将期望对指针类型使用不同的定义。但是-专业化实际上需要专业化-它不能像原始声明那样通用。就您而言,您正在添加模板参数。甚至不关乎扣减,而是您无能为力。

因此,如果您查看错误消息other compiles give you

(clang:)

<source>:7:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
struct MyClass<T> {
       ^      ~~~
<source>:6:1: error: too many template parameters in template redeclaration
template <typename T, std::size_t sz>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(MSVC:)

<source>(11): error C2753: 'MyClass<T>': partial specialization cannot match argument list for primary template
<source>(11): error C2764: 'sz': template parameter not used or deducible in partial specialization 'MyClass<T>'

您将看到错误消息措辞上的不同焦点:您必须专长,但不是。

另一方面,在第二个代码段中,您 专门研究:现在,您并没有为所有类型MyClass定义T,而仅是为一定数量的元素。您应该真正考虑一下:

template <typename U, std::size_t sz>
struct MyClass<U[sz]> {
    static void print() {
        std::cout << "Partially specialized" << std::endl;
    }
};

因此,专门化是针对T的形式为U[sz]的情况。

答案 1 :(得分:1)

  

我在想,如果初始代码是可编译的,我们可以采用诸如MyClass<int, 4>::print()之类的方式使用它。

这不是模板专门化的工作方式。如果将基本模板声明为template <class T> struct MyClass,则MyClass仅可以使用一个模板类型参数实例化。不能将其实例化为MyClass<int, int>MyClass<int, 3>MyClass<3>

模板专业化可以仅对基本模板参数进行专业化

回到您的问题。因此MyClass可以像这样被实例化:MyClass<int>MyClass<float>MyClass<SomeClass>MyClass<int*>MyClass<int[10]>,依此类推。 >

写作时

template <typename T, std::size_t sz>
struct MyClass<T[sz]> { 

您将模板MyClass<T>专用于数组或任何大小的任何T。例如MyClass<int[24]>将使用这种专业化。

撰写时

template <typename T, std::size_t sz>
struct MyClass<T> {
//             ^
//             no sz here

这看起来像是MyClass的专业化,但不是,因为sz没有出现在专业化参数中。