简体   繁体   English

C ++嵌套模板问题

[英]C++ nested template issue

GCC 7.3.1 compile the below code while clang 8.0.0 does not. GCC 7.3.1编译以下代码,而clang 8.0.0不会。 I would like to know if this syntax is valid (in which case I will report it as a possible clang bug). 我想知道此语法是否有效(在这种情况下,我将其报告为可能的clang错误)。

Thanks for your help. 谢谢你的帮助。

template<typename FOO>
struct Foo
{
  using Value = int;

  template<Value VALUE>
  struct Bar;
};

template<typename FOO>
template<typename Foo<FOO>::Value VALUE>
struct Foo<FOO>::Bar { static void test(); };

template<typename FOO>
template<typename Foo<FOO>::Value VALUE>
void Foo<FOO>::Bar<VALUE>::test() {}

int main() { return 0; }

The error message with clang is the following: 带有c的错误消息如下:

error: nested name specifier 'Foo<FOO>::Bar<VALUE>::' for declaration does not refer into a class, class template or class template partial specialization
void Foo<FOO>::Bar<VALUE>::test() {}
     ~~~~~~~~~~~~~~~~~~~~~~^
1 error generated.

EDIT: clang possible bug report here . 编辑: 这里可能有bug报告。

From [temp.mem.class/1] , we have [temp.mem.class / 1]开始

A member class of a class template may be defined outside the class template definition in which it is declared. 类模板的成员类可以在声明它的类模板定义之外定义。

Furthermore, in a non-template context, [class.nest/2] tells us: 此外,在非模板上下文中, [class.nest / 2]告诉我们:

Member functions and static data members of a nested class can be defined in a namespace scope enclosing the definition of their class. 嵌套类的成员函数和静态数据成员可以在包含其类定义的名称空间范围内定义。

Let's hence construct a simpler example and verify that the definition of a member function of a nested type is allowed to be separated from the definition of the nested, non-template type itself. 让因此的构造简单的例子,并验证嵌套类型的成员函数的定义允许从嵌套非模板类型本身的定义分开。 In analogy to the types in your snippet: 与代码段中的类型类似:

template <class FOO>
struct Foo {
   // Simpler, Bar is not a template
   struct Bar;
};

// Definition of Bar outside of Foo as before
template <class FOO>
struct Foo<FOO>::Bar {
   static void test(); 
};

And now the critical part, the definition of Bar::test() outside of Bar itself: 现在关键的部分是Bar本身之外的Bar Bar::test()的定义:

template <class FOO>
void Foo<FOO>::Bar::test() { }

This happily compiles with both gcc-8 and clang (trunk as well as a much older stable version). 可以用gcc-8clang (trunk以及更老的稳定版本)愉快地进行编译。

I might be misunderstanding something here, but my conclusion is that the syntax to define Foo::Bar::test() outside of Foo and outside of Bar is indeed fine, and clang should compile it as gcc does. 我可能在这里误解了一些东西,但是我的结论是,在Foo外部和Bar外部定义Foo::Bar::test()的语法确实很好,并且clang应该像gcc一样编译它。

This is an interesting case! 这是一个有趣的案例! My position whether it is a compiler or standard problem is similar to @lubgr, but I wanted to add some more insights. 无论是编译器问题还是标准问题,我的立场都类似于@lubgr,但我想补充一些见解。

ICC also have some problems with your construct, which might suggest that this is more deeply rooted in standard (still, gcc might be correct here). ICC的构造也存在一些问题,这可能表明它在标准中有更深的扎根(不过,gcc在这里可能是正确的)。 It fails with error: "template argument list must match the parameter list" - this might mean that for both compilers this: 它失败并显示错误:“模板参数列表必须与参数列表匹配”-这可能意味着对于两个编译器而言:

template<typename FOO>
template<typename Foo<FOO>::Value VALUE>

are not identical with original definition of Foo . Foo原始定义不同。 It seems to be a bug of both compilers, but I've learned to be cautious when two different compilers share similar problems. 这似乎是两个编译器的错误,但是当两个不同的编译器共享相似的问题时,我学会了谨慎。

Extracting definition of Value from original template to separate one fixes the case ( code on Compiler Explorer ): 从原始模板中提取Value定义以单独解决一个问题( Compiler Explorer上的代码 ):

template<typename T>
struct X
{
    using Value = int;
};

template<typename FOO>
struct Foo
{    
  template<typename X<FOO>::Value VALUE>
  struct Bar;
};

template<typename FOO>
template<typename X<FOO>::Value VALUE>
struct Foo<FOO>::Bar { static void test(); };

template<typename FOO>
template<typename X<FOO>::Value VALUE>
void Foo<FOO>::Bar<VALUE>::test() {}

int main() { return 0; }

You can fix this as well by simply using hardcoded Value type ( code on Compiler Explorer ) - but this is not what you need probably: 您也可以通过使用硬编码的Value类型( Compiler Explorer上的代码 )来解决此问题-但这可能不是您所需要的:

template<typename FOO>
struct Foo
{    
  template<int VALUE>
  struct Bar;
};

template<typename FOO>
template<int VALUE>
struct Foo<FOO>::Bar { static void test(); };

template<typename FOO>
template<int VALUE>
void Foo<FOO>::Bar<VALUE>::test() {}

int main() { return 0; }

Hope it helps! 希望能帮助到你!

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

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