要在派生类模板中使用依赖基类中的名称(例如B<T>
),必须向编译器添加一个前缀突出显示的依赖名称(B<T>::
)。为了避免多次执行此操作,可以使用 using 声明。
下面的代码带有这样的使用声明:
template <class T>
struct A {
constexpr static int x = 0;
};
template <class T>
struct B : A<T> {
// ok everywhere
constexpr static int y = B<T>::x;
// ok in MSVC
using B<T>::x;
constexpr static int z = x;
};
在 MSVC 编译器中运行良好,但其他人不喜欢它。Clang 尤其抱怨
错误:'B' 中没有名为 'x' 的成员
y = B<T>::x
但是 Clang 在上面一行中没有看到任何错误。在线演示: https ://gcc.godbolt.org/z/PvKW753M8
这里哪种实现是正确的以及为什么?
该程序是 IFNDR(格式不正确,无需诊断)。
这是因为您从未实例化任何特化,但特化的每个实例化
B
都是错误的。请参阅[temp.res.general]/6.1。每个实例化都是格式错误的,因为命名当前实例化(即当前类),而不是其基类,但类范围中声明中的嵌套名称说明
B<T>
符的左侧必须命名当前类的基类(或整个名称必须命名枚举器)。请参阅[namespace.udecl]/3。using