以下代码被 VC++ 2013 接受,但被 clang 3.4 拒绝。
哪个编译器符合 C++ 标准?
template<class T>
struct A
{
T n;
};
template<class T>
struct B : A<T>
{
// VC++ 2013 : OK
// clang : error : use of class template 'A' requires template arguments
B& f1(const A& obj)
{
return *this;
}
// VC++ : OK
// clang : OK
B& f2(const A<T>& obj)
{
return *this;
}
};
int main()
{
B<int> b;
}
最佳答案
我的第一直觉是说 VC++ 是正确的。名称查找A
在 B
应该找到 injected-class-name A
里面 A<T>
, 也可以用作 type-name 来引用 A<T>
.
C++11 [temp.local]:
1 Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in
<>
.2 ...
3 The injected-class-name of a class template or class template specialization can be used either as a template-name or a type-name wherever it is in scope. [ Example:
template <class T> struct Base { Base* p; }; template <class T> struct Derived: public Base<T> { typename Derived::Base* p; // meaning Derived::Base<T> };
然而,与此同时,[temp.dep]§3 指出:
3 In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.
基于此,我更倾向于说 clang 实际上是正确的,因为注入(inject)的类名 A
在 A<T>
的范围内, 这取决于 B
的模板参数T
因此在非限定名称查找期间不搜索。支持这一点的次要证据是 [temp.local] 中的示例使用 Derived::Base
。而不仅仅是Base
.
所以总的来说,我会这么说
这是一个很好的角落案例,并且
clang 不检查
A<T>
的范围其实是对的
关于c++ - 如果基类是成员函数的参数类型,是否需要指定基类的模板参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24307512/