我今天正在玩模板,看看我是否可以让编译器从其内部类中推断出外部类的类型。 我没有找到我的解决方案(我怀疑是不可能的),但在尝试修复错误时,我遇到了非常奇怪的行为,我沦为下面的代码片段。
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。
然后我使用这个简单的测试来获得InnerProblem
和OuterProblem
的确切类型:
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::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; //不行
答案 0 :(得分:6)
它有效。
类名也插入到类本身的范围内; 这被称为注入类名。&#34; (9/2)。
所以B::B
为B
类命名,B::B::B
也是如此,等等。
编辑:
所以typename B::B
为B
类命名,typename B::B::B
也是如此,等等。