模板相关的基本成员未正确解析

时间:2016-11-07 17:06:33

标签: c++ c++11 templates

这个问题是后续问题 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(){}

Live on Coliru

令人困惑的是,即使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中,解析器认为我们正在尝试实例化一个模板(<符号),而我们忘记关闭>。但是再次不知道这确实是一个错误还是该语言如何起作用。

1 个答案:

答案 0 :(得分:7)

tl; dr 看起来这是一个深思熟虑的决定,专门用于支持您已使用的替代语法。

以下标准的大致演练:

this-> B <
         ^
  • 这可能是模板ID的开头或者是小于的,所以让我们检查两者!
    1. this->B确实命名,但它是一个模板B<T>,所以继续
    2. B上也有自己的名字,类模板B<T>
    3. 等等,他们是一回事!这意味着我们使用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并失败。