今天我在尝试使用模板来让编译器从内部类中推断出外部类的类型,虽然最终没有找到解决方案(我猜可能是不可能实现的),但在尝试修复一个错误时,我遇到了非常奇怪的行为,我将其简化为以下代码片段。
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
,没有任何警告或错误。我发现它也可以在Ideone上使用C++14设置编译而不出问题。
然后,我使用了这个简单的测试来获取
InnerProblem
和OuterProblem
的确切类型:template <class T> void Type();
int main()
{
Type<A::InnerProblem>();
Type<A::OuterProblem>();
}
两个编译器在编译测试时报告相同的类型:
在函数
main
中:
main.cpp:20: undefined reference tovoid Type<A::B>()
main.cpp:21: undefined reference tovoid 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'表示构造函数,而不是类型 using InnerProblem = EverythingIsFine::Inner::B::B::B; // 不正确