C ++嵌套模板问题

问题描述 投票:8回答:2

GCC 7.3.1编译下面的代码,而clang 8.0.0没有。我想知道这个语法是否有效(在这种情况下,我会将其报告为可能的clang bug)。

谢谢你的帮助。

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

clang的错误消息如下:

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.

编辑:clang可能的错误报告here

c++ templates g++ language-lawyer clang++
2个回答
1
投票

这是一个有趣的案例!我的位置是编译器还是标准问题类似于@lubgr,但我想添加一些更多的见解。

ICC在构造方面也存在一些问题,这可能表明这在标准中更为根深蒂固(仍然,gcc在这里可能是正确的)。它失败并出现错误:“模板参数列表必须与参数列表匹配” - 这可能意味着对于两个编译器:

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

Foo的原始定义不同。这似乎是两个编译器的错误,但是当两个不同的编译器共享类似的问题时,我学会了谨慎。

从原始模板中提取Value的定义到单独的一个修复案例(code on 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; }

您可以通过简单地使用硬编码的Value类型(code on 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; }

希望能帮助到你!


2
投票

来自[temp.mem.class/1],我们有

可以在声明它的类模板定义之外定义类模板的成员类。

此外,在非模板环境中,[class.nest/2]告诉我们:

嵌套类的成员函数和静态数据成员可以在包含其类定义的命名空间范围内定义。

因此,让我们构造一个更简单的示例,并验证嵌套类型的成员函数的定义是否允许与嵌套的非模板类型本身的定义分开。与您的代码段中的类型类似:

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(); 
};

现在关键部分,Bar::test()本身之外的Bar的定义:

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

这很快乐地汇编了gcc-8clang(行李箱以及更老的稳定版本)。

我可能在这里误解了一些东西,但我的结论是在Foo::Bar::test()之外和Foo之外定义Bar的语法确实很好,clang应该像gcc那样编译它。

© www.soinside.com 2019 - 2024. All rights reserved.