简体   繁体   English

局部模板指定的编译器错误(C ++)

[英]Compiler errors on partial template speciailzation (c++)

I am trying to do a simple partial template specialization, but I get errors on g++4.4.7, g++4.8.5, clang++3.8.0. 我试图做一个简单的局部模板专门化,但是在g ++ 4.4.7,g ++ 4.8.5,clang ++ 3.8.0上出现错误。 Whenever I mention compiler(s) error, I mean the output of all of these, as they always agree. 每当我提到编译器错误时,我都是指所有这些的输出,因为它们总是一致的。 I am using C++03, compiling without any option. 我正在使用C ++ 03,没有任何选择地进行编译。

The code: 编码:

#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;
}

Question 1: This code fails to compile. 问题1:此代码无法编译。 The compilers say that A<int, float> and A<int> are wrong as A requires 3 templates parameters. 编译器说A<int, float>A<int>是错误的,因为A需要3个模板参数。 Why? 为什么?

If I change the original declaration to 如果我将原始声明更改为

template <typename T, typename X = void, typename G = void>
struct A {};

The code compiles and the output is: 1 | 2 代码经过编译,输出为: 1 | 2 1 | 2 . 1 | 2

What happens is that the compiler in a first step matches one and two type to the not specialized A , but then it correctly decides to use the code of the partially specialized class one would expect it to use. 发生的情况是,编译器首先将one类型和two类型与未专用的A匹配,但是随后它正确地决定使用希望使用的部分专用类的代码。 But it should not need the defaults. 但是它不需要默认值。

I then decide to change the last partial specialization switching the first and second parameter: 然后,我决定更改第一个和第二个参数,以更改最后的部分专业化:

template <typename X>
struct A<void, X, void> { A() : n(2) {} X n; };

I would expect this to change nothing, but the compilers disagree. 我希望这不会改变任何东西,但是编译器不同意。 The clearest output between the 3 is here reported: 此处报告了这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.

Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A that specializes only one argument? 问题2:为什么编译器将two变量视为A的部分专业化实例的一部分,该实例仅专门化一个参数?

Note that is the "2nd matching", because if I only use 1 default template argument, the compiler will go back to complaining about the fact that 3 template parameters are needed. 请注意,这是“第二次匹配”,因为如果我仅使用1个默认模板参数,则编译器将回过头来抱怨需要3个模板参数这一事实。

Thanks. 谢谢。

Question 1: This code fails to compile. 问题1:此代码无法编译。 The compilers say that A<int, float> and A<int> are wrong as A requires 3 templates parameters. 编译器说A<int, float>A<int>是错误的,因为A需要3个模板参数。 Why? 为什么?

Because A requires 3 template parameters. 因为A需要3个模板参数。 You declared A as: 您将A声明为:

template <typename T, typename X, typename G>
struct A {};

There is no two- or one-template parameter version of A . 有没有二维或一模板参数版本的A There are versions specialized on some of the types being void , but that's still a parameter - not an absence of parameter. 有一些版本专门针对某些类型为void的类型,但这仍然是一个参数-并非缺少参数。

When you add the defaults, then A<int, float> evaluates as A<int, float, void> , which is a valid instantiation - and picks the specialization which sets n to 1. 添加默认值后, A<int, float>计算结果为A<int, float, void> ,这是有效的实例化-并选择将n设置为1的特殊化。

You're misunderstanding how specialization works. 您误会了专业化的工作原理。 Specialization doesn't change the number of template parameters. 专业化不会更改模板参数的数量。 It's just a way of adding special functionality depending on what the template parameters end up being. 这只是根据最终模板参数添加特殊功能的一种方式。

Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A that specializes only one argument? 问题2:为什么编译器将两个变量视为A的部分专业化实例的一部分,该实例仅专门化一个参数?

We have three choices 我们有三个选择

template <T, X, G>       struct A; // the primary
template <T, X, void>    struct A; // (1)
template <void, X, void> struct A; // (2)

When we instantiate A<int> , that is the same as A<int, void, void> when we add in the default parameters. 实例化A<int> ,与添加默认参数时的A<int, void, void>相同。 That does not match (2) - because that one requires the first parameter to be void and yours is int . 那不匹配(2) -因为那个要求第一个参数为void并且您的参数为int (1) is a better match than the primary since it's more specialized. (1)比主要版本更好,因为它更专业。 But then, (1) has a member of type X and in this case X is deduced as void (from the default parameter), and that's not allowed. 但是, (1)具有类型X的成员,在这种情况下, X被推导为void (从默认参数),这是不允许的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM