9

我的问题可以通过以下代码恢复:

template <typename T> struct C2;

template <typename T> 
struct C1
{
  template <typename Type,
        template <typename Ti> class Container = C2>
  void m() {}
};


template <typename T> 
struct C2
{
  template <typename Type = int,
        template <typename Ti> class Container = C2> // <-- Here is the problem!
  void m() {}

};

gnu 编译器,版本 4.8.1 失败并显示以下消息:

test-temp.C:16:47: error: invalid use of type ‘C2<T>’ as a default value for a template template-parameter
      template <typename Ti> class Container = C2> 

它引用方法 C2::m 的默认模板参数 C2。

显然(我认为),编译器将C2<T>其视为默认参数而不是C2(没有<T>)。因此,当它找到指令时,它会失败,因为类型C2<T>Container.

然而,clang++,只是对于完全相同的代码,编译得很好!

我的问题:

  1. 哪个编译器有真相?
  2. 是否有其他方法可以与当前版本的 gnu 编译器表达相同的含义?

提前致谢

莱安德罗

4

2 回答 2

9

我认为 Clang 是正确的,而 g++ 是错误的,引用标准草案(粗体强调是我的)

14.6.1 本地声明的名称 [temp.local]

1 与普通(非模板)类一样,类模板具有注入类名称(第 9 条)。注入的类名可以用作模板名或类型名。当它与模板参数列表一起使用时,作为模板模板参数的模板参数,或作为朋友类模板声明的详细类型说明符中的最终标识符,它指的是类模板本身。否则,它相当于模板名称后跟 <> 中包含的类模板的模板参数。

您可以使用::范围解析运算符击败 g++ 提交

template <typename T> 
struct C2
{
  template <typename Type = int,
        template <typename Ti> class Container = ::C2> 
                                              // ^^ <-- here is the solution!
  void m() {}

};

活生生的例子

于 2013-09-25T19:47:10.530 回答
0

那么 TemplateRex 答案中的 14.6.1 引用是否意味着 G++ 是正确的(而 Clang 和 VC++ 是错误的)可以接受这一点,因为它使用 X 作为模板模板参数的模板参数?

template< template< typename > class T >
class factory { };

template< typename T >
class X
{
      friend class factory< X >;  // ***
};

int main()
{
}

在此示例中,G++ 将 X 视为类模板的名称,而 Clang 和 VC++ 将其视为注入的类名。

编辑:Clang 5.0.0 现在接受代码,与 G++ 和 EDG 相同。

于 2013-09-26T09:26:44.007 回答