这个问题是后续问题
Moving a member function from base class to derived class breaks the program for no obvious reason(这是一个不应该使用using namespace std;
的原因的一个主要例子)
其中答案建议通过this->
限定一个依赖模板名称(这确实是引用此类依赖成员时的方式)。但是,似乎存在问题,因此我将列出一个可以重现问题的最小示例。
考虑代码:
#include <iostream>
#include <bitset>
using namespace std;
template<class T>
struct B
{
T bitset{};
};
template<class T>
struct D : B<T>
{
bool foo()
{
return this->bitset < 32;
}
};
int main(){}
令人困惑的是,即使this->bitset
应该引用成员B<T>::bitset
,编译器仍然感到困惑,并认为我们试图引用std::bitset<std::size_t>
。错误出现在gcc6和clang3.7上。任何想法为什么会这样?使用B<T>::bitset
对其进行限定无效。
错误(逐字):
In member function 'bool D<T>::foo(T, std::__cxx11::string)': cpp/scratch/minimal.cpp:24:22: error: invalid use of 'class std::bitset<1ul>'
修改
这对我来说就像一个解析/名称查找错误。如果我们用任何其他比较运算符替换<
(感谢@Leon的注释),例如
return this->bitset == 32;
程序编译。所以我想在this->bitset < 32
中,解析器认为我们正在尝试实例化一个模板(<
符号),而我们忘记关闭>
。但是再次不知道这确实是一个错误还是该语言如何起作用。
答案 0 :(得分:7)
tl; dr 看起来这是一个深思熟虑的决定,专门用于支持您已使用的替代语法。
以下标准的大致演练:
this-> B <
^
this->B
确实命名,但它是一个模板B<T>
,所以继续B
上也有自己的名字,类模板B<T>
this->B<T>
作为限定符, 在另一种情况下,
this->bitset
以相同的方式进行 直到第三步,当它意识到有两个不同的事物称为bitset
(模板类成员和类模板),并且放弃了。
这是来自我躺着的工作草案,所以不一定是最近的,但是:
3.4.5类成员访问[basic.lookup.classref]
的上下文中查找
1
在类成员访问表达式(5.2.5)中,如果是。或 - &gt;令牌立即 后跟一个标识符后跟一个&lt; ,标识符必须是 抬头确定是否&lt;是模板的开始 参数列表(14.2)或小于运算符。标识符是第一个 在对象表达式的类中查找。如果标识符是 没有找到,然后在整个上下文中查找 postfix-expression并命名一个类模板。 如果在中查找 对象表达式的类找到模板,名称也是 在整个postfix-expression和
- 如果找不到名称,则使用在对象表达式的类中找到的名称,否则使用
- 如果在整个postfix-expression的上下文中找到该名称,并且没有命名类模板, 使用在对象表达式的类中找到的名称,否则使用
- 如果找到的名称是一个类模板,它应该引用与该类中找到的实体相同的实体 对象表达式,否则程序格式不正确。
因此,在任何类似this->id < ...
的表达式中,它必须处理id<...
是模板标识符开头的情况(如this->B<T>::bitset
)。
它仍会先检查对象,但如果this->id
找到模板,则会采用其他步骤。在您的情况下,this->bitset
可能被视为模板,因为它仍然取决于T
,因此它会在上面的第三个项目符号中找到冲突的std::bitset
并失败。