命名空间和类模板之间的名称冲突:不同的编译器行为

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

不同的编译器show different behavior编译以下代码:

namespace N
{
    namespace Foo
    {
        template <typename>
        struct Foo
        {
        };
    }
}

template <typename Type>
using Foo = N::Foo::Foo<Type>;

namespace N
{
    template <typename Type>
    struct Bar : Foo<Type>
    {
    };
}


int main()
{
}

测试编译器及其编译标志:

  • clang ++ 5.0.0:-std=c++14 -Wall -Wextra -Werror -pedantic-errors
  • g ++ 7.2:-std=c++14 -Wall -Wextra -Werror -pedantic-errors
  • vc ++ 19.10.25017(VS 2017):/EHsc /Za /std:c++14 /permissive-
  • Ichhe 18.0.0:Coxspoi

汇编结果:

  • clang ++: -std=c++14 -Wall -Werror
  • g ++:成功编译
  • vc ++: 18 : <source>:18:15: error: expected class name struct Bar : Foo ^
  • icc:成功编译

哪种编译器行为符合标准?

附加信息:

  • 18 : <source>(18): error C2516: 'Foo': is not a legal base class 13 : <source>(13): note: see declaration of 'Foo' 20 : <source>(20): note: see reference to class template instantiation 'N::Bar<Type>' being compiled 18 : <source>(18): error C2143: syntax error: missing ',' before '<'
  • same code with anonymous namespaces
  • same code without templates
c++ templates namespaces c++14 language-lawyer
2个回答
5
投票

规范说

在查找基类名称期间,将忽略非类型名称([basic.scope.hiding])

名字是same code without templates and with anonymous namespaces,它是一个类型名称。名称Foo<Type>不是类型名称,因此必须将其忽略。在忽略某些名称的类似情况下,措辞更明确

如果嵌套名称说明符中的:: scope resolution运算符前面没有decltype-specifier,那么查找::之前的名称只会考虑其特化是类型的名称空间,类型和模板

在这里,当它想要允许N::Foo时,它不仅会说“类型名称”或“非类型名称”。但它具体说明了“专业化类型的模板”。我认为这种混淆是这里实现分歧的原因。名称type-template<arguments>是我称之为“复合名称”的名称,因为它由内部的嵌套名称组成。因此,可能不清楚其中的哪些确切名称被忽略,哪些不被忽略。


1
投票

在查找Foo<Type>之前查找名称FooFoo<Type>的查找不是基类名称的查找,因此[class.derived] / 2中的查找规则不适用。

参考[basic.lookup.unqual] / 7:

在成员函数体外定义类X的名称,默认参数,noexcept-specifier,非静态数据成员的brace-or-equal-initializer,或嵌套类定义25,应在其中一个中声明。以下方式:

  • 在X类中使用之前或者是X([class.member.lookup])的基类的成员之前,或者
  • 如果X是Y类的嵌套类,在Y中定义X之前,或者应该是Y的基类的成员(此查找依次应用于Y的封闭类,从最内层的封闭类开始),26或
  • 如果X是本地类或是本地类的嵌套类,则在包含X类定义的块中定义类X之前,或者
  • 如果X是命名空间N的成员,或者是N的成员的类的嵌套类,或者是定义之前的N的成员的函数的本地类中的本地类或嵌套类在命名空间N中的类X或在N的封闭命名空间之一中。

[实施例:

Foo

- 结束例子]

命名空间namespace M { class B { }; } namespace N { class Y : public M::B { class X { int a[i]; }; }; } // The following scopes are searched for a declaration of i: // 1) scope of class N​::​Y​::​X, before the use of i // 2) scope of class N​::​Y, before the definition of N​::​Y​::​X // 3) scope of N​::​Y's base class M​::​B // 4) scope of namespace N, before the definition of N​::​Y // 5) global scope, before the definition of N 在全局命名空间之前被考虑,因此首先找到N,这导致程序格式错误。

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