以下代码是gcc错误吗? 检查T类型是否为未定义的类Circle,返回false。
#include <iostream>
using namespace std;
// uncomment to work
//struct Circle;
struct T_traits
{
template<typename T>
constexpr static id() { return is_same<T, class Circle>(); }
};
struct Circle{};
int main()
{
cout << T_traits::id<Circle>() << "\r\n";
return 0;
}
答案 0 :(得分:5)
return is_same<T, class Circle>();
当您注释掉全局声明时,这实际上会声明一个名为Circle
的本地类。 [basic.lookup.elab] / 2:
如果 elaborated-type-specifier 没有嵌套名称说明符, 除非 elaborated-type-specifier 出现在声明中 以下形式:
中所述
class-key attribute-specifier-seq opt 标识符;
根据3.4.1查找标识符,但忽略任何非类型 已经宣布的名字。[..]
如果 class-key 引入 elaborated-type-specifier 并且此查找找不到先前声明的类型名称 [...] elaborated-type-specifier 是一个声明 引入 class-name ,如3.3.2。
查找是§3.4.1中定义的简单非限定名称查找。查找是在T_traits
的定义上下文中完成的,因为我们没有处理依赖内容,因此从不考虑Circle
之前main
的声明。
§3.3.2/ 7(别名[basic.scope.pdecl] / 7):
首先在一个声明中声明一个类的声明 elaborated-type-specifier 如下:
表格的详细说明类型
类密钥标识符
如果在中使用了 elaborated-type-specifier 在命名空间作用域中定义的函数的 decl-specifier-seq 或 parameter-declaration-clause ,标识符声明为 包含声明的命名空间中的 class-name ; 否则,除了作为朋友声明之外,标识符是在最小的命名空间或包含该范围的块范围中声明的 宣言。 [注意:这些规则也适用于模板。 - 结束 注意]
但是,删除class
关键字也不起作用 - 如前所述,标识符不依赖,因此在定义上下文中查找。如果此查找未找到任何声明,则必须由编译器发出诊断 - 即使没有实例化专门化。