当模板 class 的特化允许使用比声明的更多的模板参数时?

When specialization of template class is allowed with more template arguments than it's been declared?

代码非常简洁明了(YATC表示yet another template class:)

template<typename T1, typename T2>
class YATC; /*declaration*/

template<typename T1>
class YATC<T1,T1> {}; 

template<typename T1, typename T2, typename T3>
class YATC<T1, YATC<T2, T3>> {};

int main()
{
    YATC<int, YATC<int, double>> yatc;
    return 0;
}

这个黑魔法看起来让我很不安。

为什么这样的声明仍然有效,但为什么我不能用实例化class YATC<int, int, double>?

I've expected that I can make specializations for YATC class based on idea that I can specificate definition of the class on two template arguments only;

这是正确的。

I've found out that actually I can make specialization using infinite template arguments like typename T1, typename T2, typename T3 but with some interesting restrictions:

是的...但仍然 YACT 只有两个模板参数

参加你的第二个专业

template<typename T1, typename T2, typename T3>
class YATC<T1, YATC<T2, T3>> {};

您使用了三个模板参数,但 YACT 只收到两个模板参数:

  1. T1
  2. YACT<T2, T3>

第二个比较复杂,通过 YACT 本身和几个特化的模板参数来表达,但是 YACT<T2, T2> 仍然是一个模板参数,来自 YACT观点

实质上,声明

template<typename T1, typename T2>
class YATC;

您声明 YACT 正好接收两种类型;没有什么可以禁止你以非常非常复杂的方式构建你的类型

//                1                                  2
//...vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv..vvvvvvvvvvvvvvvvvvvvvvvvv
YACT<std::tuple<YACT<int, long>>, char>, std::vector<std::string>>> foo;

并声明 YACT 使用大量模板参数(不仅是类型,还有值和模板模板)的特化,来表达一对 YACT 类型参数。但是 YACT 必须接收 exaclty 两种类型的参数。很复杂,但恰好是两个。

I still cannot insatiate the class with YATC<int, int, double>, only YATC<int, YATC<int, double>>;

完全正确。

因为

//    1    2      3
// ..VVV..VVV..VVVVVV
YATC<int, int, double>

您将 三个 类型传递给 YACT,但

//    1           2
// ..VVV..VVVVVVVVVVVVVVVVV
YATC<int, YATC<int, double>>

你将两种类型传递给YACTYACT<int, double>是一种类型)。

因为 YATC 仍然被声明为采用两个模板参数,尽管专业化误导了您的想法。

将专业化视为自身模板化可能会有所帮助。为了让您了解我的意思,请考虑:

template<typename T1, typename T2>
class YATC;

此处 YATC 的特化是使用两种类型构建的 - T1T2

template<typename T1, typename T2, typename T3>
class YATC<T1, YATC<T2, T3>> {};

这里,专业化确实有三个模板参数——T1T2T3。但是,YATC 本身仍然只接受两个模板参数 - T1YATC<T2, T3>.

因此,直接回答您的问题,声明 template<typename T1, typename T2, typename T3> class YATC<T1, YATC<T2, T3>> 实际上并没有声明 YATC 为采用三个参数的模板。在某种程度上,特化本身可以被认为是一个带有三个参数的模板,尽管这些参数总是在构建特化时隐式填充。