当模板 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 声明为具有两个模板参数的模板 class T1
,T2
;
我预计我 可以根据我可以指定class 仅两个模板参数;
我发现实际上我可以使用像 typename T1, typename T2, typename T3
这样的无限模板参数进行专业化,但有一些有趣的限制:
我不能使用 std::common_type_t<T1, T2>
作为 YATC
专业化的第二个参数。编译器抛出 T2
未用于 YATC
的特化的错误;
但是,我可以使用它们对接收这些参数的某些模板 class 的实例进行专业化(如 YATC<T2, T3>
);
但是!我仍然无法用 YATC<int, int, double>
实例化 class,只能 YATC<int, YATC<int, double>>
;
为什么这样的声明仍然有效,但为什么我不能用实例化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
只收到两个模板参数:
T1
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>>
你将两种类型传递给YACT
(YACT<int, double>
是一种类型)。
因为 YATC
仍然被声明为采用两个模板参数,尽管专业化误导了您的想法。
将专业化视为自身模板化可能会有所帮助。为了让您了解我的意思,请考虑:
template<typename T1, typename T2>
class YATC;
此处 YATC
的特化是使用两种类型构建的 - T1
和 T2
。
template<typename T1, typename T2, typename T3>
class YATC<T1, YATC<T2, T3>> {};
这里,专业化确实有三个模板参数——T1
、T2
和T3
。但是,YATC
本身仍然只接受两个模板参数 - T1
和 YATC<T2, T3>
.
因此,直接回答您的问题,声明 template<typename T1, typename T2, typename T3> class YATC<T1, YATC<T2, T3>>
实际上并没有声明 YATC
为采用三个参数的模板。在某种程度上,特化本身可以被认为是一个带有三个参数的模板,尽管这些参数总是在构建特化时隐式填充。
代码非常简洁明了(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 声明为具有两个模板参数的模板 class
T1
,T2
;我预计我 可以根据我可以指定class 仅两个模板参数;
我发现实际上我可以使用像
typename T1, typename T2, typename T3
这样的无限模板参数进行专业化,但有一些有趣的限制:我不能使用
std::common_type_t<T1, T2>
作为YATC
专业化的第二个参数。编译器抛出T2
未用于YATC
的特化的错误;但是,我可以使用它们对接收这些参数的某些模板 class 的实例进行专业化(如
YATC<T2, T3>
);但是!我仍然无法用
YATC<int, int, double>
实例化 class,只能YATC<int, YATC<int, double>>
;
为什么这样的声明仍然有效,但为什么我不能用实例化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
只收到两个模板参数:
T1
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>
, onlyYATC<int, YATC<int, double>>
;
完全正确。
因为
// 1 2 3
// ..VVV..VVV..VVVVVV
YATC<int, int, double>
您将 三个 类型传递给 YACT
,但
// 1 2
// ..VVV..VVVVVVVVVVVVVVVVV
YATC<int, YATC<int, double>>
你将两种类型传递给YACT
(YACT<int, double>
是一种类型)。
因为 YATC
仍然被声明为采用两个模板参数,尽管专业化误导了您的想法。
将专业化视为自身模板化可能会有所帮助。为了让您了解我的意思,请考虑:
template<typename T1, typename T2>
class YATC;
此处 YATC
的特化是使用两种类型构建的 - T1
和 T2
。
template<typename T1, typename T2, typename T3>
class YATC<T1, YATC<T2, T3>> {};
这里,专业化确实有三个模板参数——T1
、T2
和T3
。但是,YATC
本身仍然只接受两个模板参数 - T1
和 YATC<T2, T3>
.
因此,直接回答您的问题,声明 template<typename T1, typename T2, typename T3> class YATC<T1, YATC<T2, T3>>
实际上并没有声明 YATC
为采用三个参数的模板。在某种程度上,特化本身可以被认为是一个带有三个参数的模板,尽管这些参数总是在构建特化时隐式填充。