Dir*_*ich 2 c++ templates partial-specialization
我试图做一个简单的部分模板专业化,但我在g ++ 4.4.7,g ++ 4.8.5,clang ++ 3.8.0上遇到错误.每当我提到编译器错误时,我的意思是所有这些的输出,因为他们总是同意.我正在使用C++ 03,没有任何选项进行编译.
代码:
#include <iostream>
template <typename T, typename X, typename G>
struct A {};
template <typename T, typename X>
struct A<T, X, void> { A() : n(1) {} X n; T b; };
template <typename X>
struct A<X, void, void> { A() : n(2) {} X n; };
int main() {
A<int, float> one;
A<int> two;
std::cout << one.n << " | " << two.n << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
问题1:此代码无法编译.编译器说,A<int, float>和A<int>是错误的,A需要3个模板参数.为什么?
如果我将原始声明更改为
template <typename T, typename X = void, typename G = void>
struct A {};
Run Code Online (Sandbox Code Playgroud)
代码编译,输出为:1 | 2.
会发生的是,第一步中的编译器匹配one并two键入非专用的A,但它正确地决定使用人们期望它使用的部分专用类的代码.但它不应该需要默认值.
然后我决定更改最后一个部分特化切换第一个和第二个参数:
template <typename X>
struct A<void, X, void> { A() : n(2) {} X n; };
Run Code Online (Sandbox Code Playgroud)
我希望这不会改变,但编译器不同意.这里报告了3之间最清晰的输出:
a.cpp:7:40: error: field has incomplete type 'void'
struct A<T, X, void> { A() : n(1) {} X n; T b; };
^
a.cpp:14:10: note: in instantiation of template class 'A<int, void, void>' requested here
A<int> two;
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
问题2:为什么编译器将two变量视为A的部分特化的一个实例,它只专用一个参数?
请注意,这是"第二次匹配",因为如果我只使用1个默认模板参数,编译器将回过头来抱怨需要3个模板参数这一事实.
谢谢.
问题1:此代码无法编译.编译器说,
A<int, float>和A<int>是错误的,A需要3个模板参数.为什么?
因为A需要3个模板参数.你宣称A:
template <typename T, typename X, typename G>
struct A {};
Run Code Online (Sandbox Code Playgroud)
没有双模板或单模板参数版本A.有些版本专门针对某些类型void,但这仍然是一个参数 - 而不是缺少参数.
当您添加默认值时,则A<int, float>计算为A<int, float, void>,这是一个有效的实例化 - 并选择设置n为1的特化.
你误解了专业化是如何运作的.专业化不会更改模板参数的数量.这只是添加特殊功能的一种方式,具体取决于模板参数的最终结果.
问题2:为什么编译器在考虑这两个变量的部分特化的实例时
A只专用一个参数?
我们有三个选择
template <T, X, G> struct A; // the primary
template <T, X, void> struct A; // (1)
template <void, X, void> struct A; // (2)
Run Code Online (Sandbox Code Playgroud)
当我们实例化时A<int>,这与A<int, void, void>我们添加默认参数时相同.那是不匹配的(2)- 因为那个需要第一个参数void而你的是int.(1)是一个比主要更好的匹配,因为它更专业.但是,(1)有一个类型的成员,X在这种情况下X被推断为void(来自默认参数),这是不允许的.