部分模板特化的编译器错误 (c++)
Compiler errors on partial template speciailzation (c++)
我正在尝试进行简单的部分模板特化,但在 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;
}
问题一:这段代码编译失败。编译器说 A<int, float>
和 A<int>
是错误的,因为 A
需要 3 个模板参数。为什么?
如果我把原来的声明改成
template <typename T, typename X = void, typename G = void>
struct A {};
代码编译,输出为:1 | 2
.
编译器在第一步中将 one
和 two
类型匹配到非特化的 A
,但随后它正确地决定使用部分的代码specialized class 人们会期望它使用。但它不应该需要默认值。
然后我决定更改最后一个偏特化,切换第一个和第二个参数:
template <typename X>
struct A<void, X, void> { A() : n(2) {} X n; };
我希望这不会有任何改变,但编译器不同意。此处报告了 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.
问题 2:为什么编译器将 two
变量视为仅特化一个参数的 A 的偏特化实例?
请注意这是“第二次匹配”,因为如果我只使用 1 个默认模板参数,编译器将返回抱怨需要 3 个模板参数这一事实。
谢谢。
Question 1: This code fails to compile. The compilers say that A<int, float>
and A<int>
are wrong as A
requires 3 templates parameters. Why?
因为A
需要3个模板参数。您将 A
声明为:
template <typename T, typename X, typename G>
struct A {};
A
没有两个或一个模板参数版本。有些版本专门针对某些类型 void
,但这仍然是一个参数 - 而不是缺少参数。
添加默认值后,A<int, float>
的计算结果为 A<int, float, void>
,这是一个有效的实例化 - 并选择将 n
设置为 1 的特化。
您误解了专业化的运作方式。专业化不会改变模板参数的数量。这只是一种根据模板参数最终成为什么来添加特殊功能的方法。
Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A
that specializes only one argument?
我们有三种选择
template <T, X, G> struct A; // the primary
template <T, X, void> struct A; // (1)
template <void, X, void> struct A; // (2)
当我们实例化A<int>
时,与我们在默认参数中加入A<int, void, void>
是一样的。那不匹配 (2)
- 因为那个要求第一个参数是 void
而你的是 int
。 (1)
比主匹配更好,因为它更专业。但是,(1)
有一个 X
类型的成员,在这种情况下 X
被推断为 void
(从默认参数),这是不允许的。
我正在尝试进行简单的部分模板特化,但在 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;
}
问题一:这段代码编译失败。编译器说 A<int, float>
和 A<int>
是错误的,因为 A
需要 3 个模板参数。为什么?
如果我把原来的声明改成
template <typename T, typename X = void, typename G = void>
struct A {};
代码编译,输出为:1 | 2
.
编译器在第一步中将 one
和 two
类型匹配到非特化的 A
,但随后它正确地决定使用部分的代码specialized class 人们会期望它使用。但它不应该需要默认值。
然后我决定更改最后一个偏特化,切换第一个和第二个参数:
template <typename X>
struct A<void, X, void> { A() : n(2) {} X n; };
我希望这不会有任何改变,但编译器不同意。此处报告了 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.
问题 2:为什么编译器将 two
变量视为仅特化一个参数的 A 的偏特化实例?
请注意这是“第二次匹配”,因为如果我只使用 1 个默认模板参数,编译器将返回抱怨需要 3 个模板参数这一事实。
谢谢。
Question 1: This code fails to compile. The compilers say that
A<int, float>
andA<int>
are wrong asA
requires 3 templates parameters. Why?
因为A
需要3个模板参数。您将 A
声明为:
template <typename T, typename X, typename G>
struct A {};
A
没有两个或一个模板参数版本。有些版本专门针对某些类型 void
,但这仍然是一个参数 - 而不是缺少参数。
添加默认值后,A<int, float>
的计算结果为 A<int, float, void>
,这是一个有效的实例化 - 并选择将 n
设置为 1 的特化。
您误解了专业化的运作方式。专业化不会改变模板参数的数量。这只是一种根据模板参数最终成为什么来添加特殊功能的方法。
Question 2: Why are the compilers considering the two variable an instance of the partial specialization of
A
that specializes only one argument?
我们有三种选择
template <T, X, G> struct A; // the primary
template <T, X, void> struct A; // (1)
template <void, X, void> struct A; // (2)
当我们实例化A<int>
时,与我们在默认参数中加入A<int, void, void>
是一样的。那不匹配 (2)
- 因为那个要求第一个参数是 void
而你的是 int
。 (1)
比主匹配更好,因为它更专业。但是,(1)
有一个 X
类型的成员,在这种情况下 X
被推断为 void
(从默认参数),这是不允许的。