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

时间:2016-02-02 19:39:14

标签: c++ c++11 g++ clang language-lawyer

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

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

我发现它也编译得很好on Ideone with the C++14 setting

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

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

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

  

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

的未定义引用

也就是说,InnerProblem的类型为A::BOuterProblem的类型为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; //不行

1 个答案:

答案 0 :(得分:6)

它有效。

  

类名也插入到类本身的范围内;   这被称为注入类名。&#34; (9/2)。

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

编辑:

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