6

以下代码给出了预期的编译器错误(Demo):

  1 template<bool> struct Range;
  2 
  3 template<int value, typename = Range<true> > struct Unique;
  4 template<int value> struct Unique<value, Range<(value > 1)> > { typedef char type[1]; };
  5 template<int value> struct Unique<value, Range<(value > 2)> > { typedef char type[2]; };
  6 
  7 Unique<3>::type o1;
  8 Unique<3>::type o2;

现在,如果我交换第 5 行和第 7 行。然后没有编译器错误演示

  5 Unique<3>::type o1;

  7 template<int value> struct Unique<value, Range<(value > 2)> > { typedef char type[2]; };

对于o1,没有错误是可以理解的,因为(value > 2)尚不可见 for 的特化。但是为什么也没有错误o2,它看到了 2 个匹配的专业化!?
我的猜测是,编译器第一次遇到时应该选择Unique<3>::type具有任意名称的 ,然后用Unique<3>::type该名称替换任何地方。

这是编译错误还是 C++ 错误或 C++“功能”?

4

3 回答 3

3

模板在第一次需要时(在翻译单元中)被实例化,而不是每次。

于 2012-03-06T11:16:24.177 回答
2

14.5.5.1 类模板偏特化的匹配中,有

如果找到多个匹配的特化,则使用偏序规则 (14.5.5.2) 来确定其中一个特化是否比其他特化更特化。如果没有一个特化比所有其他匹配的特化更特化,那么类模板的使用是模棱两可的并且程序是非良构的。

但是,这仅适用于您的第一种情况,其中有两个专业可见,我还不确定这两个专业本身是否有效。

但是,在您的第二种情况下,在达到第二个专业化之前,模板 ID Unique<3>已经存在,为此(感谢 nm,Matthieu M.,James Kanze)第一个专业化已经实例化:

14.5.5 类模板部分特化

部分特化应在第一次使用类模板特化之前声明,该类模板特化将使用部分特化作为出现这种使用的每个翻译单元中的隐式或显式实例化的结果;不需要诊断。

14.5.5 中,第 8 项

在类模板部分特化的参数列表中,适用以下限制:

— 部分特化的非类型实参表达式不应涉及部分特化的模板形参,除非实参表达式是简单标识符。[ >示例:

template <int I, int J> struct A {};

template <int I> struct A<I+5, I*2> {}; // error

template <int I, int J> struct B {};

template <int I> struct B<I, I> {}; // OK

—结束示例]

所以似乎非类型参数不参与专业化创建,如果不用作简单标识符(因此Range<(value > 2)>是错误的)。

因此,您的代码似乎格式不正确。


没有直接关系,但在这方面仍然很有趣:

14.7.3 显式专业化

函数模板、类模板、类模板的成员函数、类模板的静态数据成员、类模板的成员类、类模板的成员类模板、类模板的成员函数模板、成员的成员函数的显式特化声明的放置类模板的模板、非模板类的成员模板的成员函数、类模板的成员类的成员函数模板等,以及类模板的偏特化声明的放置、非模板类的成员类模板、成员类模板的类模板等,可以根据相对定位影响程序是否良构显式特化声明及其在翻译单元中的实例化点,如上文和下文所述。编写专业时,请注意其位置;或者让它编译将是一种试炼,以点燃它的自焚。

于 2012-03-06T11:23:16.047 回答
2

o1由于这个原因,没有看到第二个专业:

14.5.5/1部分特化应在第一次使用类模板特化之前声明,该类模板特化将使用部分特化作为出现这种使用的每个翻译单元中的隐式或显式实例化的结果;不需要诊断

在第二个示例中,第二个特化将用于实例化Unique<3>if 它在声明之前看到o1。由于违反了这条规则,程序就被破坏了,编译器可以对此保持沉默。

o2没有看到第二个专业化,因为它根本没有看到任何专业化。它的类在o1声明时被实例化一次。

于 2012-03-06T14:43:35.780 回答