这个荒谬的代码是否能够很好地编译Clang和GCC中的错误?

tux*_*ux3 8 c++ g++ clang language-lawyer c++11

今天我正在玩模板,看看我是否可以让编译器从其内部类中推断出外部类的类型.我没有找到我的解决方案(我怀疑是不可能的),但在尝试修复错误时,我遇到了非常奇怪的行为,我沦为下面的代码片段.

struct A
{
    struct B{};

    template <typename T>
    struct EverythingIsFine
    {
        using Outer = T;
        using Inner = typename T::B::B::B::B::B::B;
    };

    using ItWillBeOkay = EverythingIsFine<B>; // Probably not ok
    using InnerProblem = ItWillBeOkay::Inner; // Still not ok
    using OuterProblem = decltype(B().ItWillBeOkay::Outer::B::B::B
                                     ::B::B::B::~B()); // Not even CLOSE to ok
};
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,Clang和GCC都没有警告,没有任何错误.
我的编译器的版本是gcc version 5.3.1 20160121 (Debian 5.3.1-7)和,Debian clang version 3.6.2-3 (tags/RELEASE_362/final) (based on LLVM 3.6.2)并且用于编译的标志是-std=c++11 -Wall -Wextra.

我发现它在使用C++ 14设置的Ideone上编译也很好.


然后我使用这个简单的测试来获得确切的类型InnerProblemOuterProblem:

template <class T> void Type();
int main()
{
    Type<A::InnerProblem>();
    Type<A::OuterProblem>();
}
Run Code Online (Sandbox Code Playgroud)

编译测试时,两个编译器都会报告相同的类型:

在函数中main:
main.cpp:20:对void Type<A::B>()
main.cpp的未定义引用:21:未定义引用void Type<void>()

也就是说,类型InnerProblemIS A::B和的类型OuterProblemvoid.


这是标准允许的,还是两个编译器中的错误?
既然我似乎和编译器一样困惑,那么这段代码究竟发生了什么?

编辑:作为一个简化的后续,因为我不明白为什么两个编译器不能给出相同的结果,下面的代码编译与Clang,但不与GCC编译.

struct A
{
    struct B{};

    template <typename T>
    struct EverythingIsFine
    {
        using Inner = typename T::B::B::B;
    };

    using Problem = EverythingIsFine<B>::Inner::B::B::B; // Not ok
};
Run Code Online (Sandbox Code Playgroud)

GCC现在输出以下错误:

main.cpp:11:26:错误:'A :: B :: B'命名构造函数,而不是使用InnerProblem = EverythingIsFine :: Inner :: B :: B :: B的类型; // 不好

Pet*_*ker 6

这是有效的.

类名也插入到类本身的范围内; 这被称为注入类名."(9/2).

因此,B::B将类命名BB::B::B等等.

编辑:

因此,typename B::B将类命名Btypename B::B::B等等.

  • `B :: B`在这里命名一个构造函数.它只有少数情况下没有.不,这不是有效的,但是Clang被窃听了. (3认同)