这个荒谬的代码在 Clang 和 GCC 中编译得很好吗?

Is this absurd code that compiles fine a bug in both Clang and GCC?

本文关键字:编译 很好 GCC 荒谬 代码 Clang      更新时间:2023-10-16

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

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

令人惊讶的是,它的编译没有警告,也没有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 上也能很好地编译。


然后,我使用这个简单的测试来获得确切的InnerProblem类型和OuterProblem

template <class T> void Type();
int main()
{
    Type<A::InnerProblem>();
    Type<A::OuterProblem>();
}

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

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

也就是说,InnerProblem的类型是A::B的,OuterProblem的类型是void的。


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

编辑:作为一个简化的后续,因为我不明白为什么两个编译器不能给出相同的结果,下面的代码使用 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
};

GCC 现在输出以下错误:

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

它是

有效的。

名也入到类本身的作用域中; 这称为注入类名。(9/2(。

所以B::B命名类BB::B::B也是如此,等等。

编辑:

所以typename B::B把类命名为Btypename B::B::B也是如此,依此类推。

相关文章: