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

vso*_*tco 7 c++ templates c++11

这个问题是将成员函数从基类移动到派生类的后续操作 ,没有明显的原因打破程序(这是为什么不应该使用它的一个主要例子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(){}
Run Code Online (Sandbox Code Playgroud)

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; 
Run Code Online (Sandbox Code Playgroud)

该程序编译.所以我猜在this->bitset < 32解析器中认为我们正在尝试实例化一个模板(<标志),而我们忘了关闭它>.但是再次不知道这确实是一个错误,还是该语言是如何工作的.

Use*_*ess 7

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

下面标准的近似演练:

this-> B <
         ^
Run Code Online (Sandbox Code Playgroud)
  • 这可以是模板ID的开头,也可以是小于的,所以让我们检查两者!
    1. this->B确实命名,但它是一个模板B<T>,所以继续
    2. B 在它自己也命名一些东西,一个类模板 B<T>
    3. 等等,他们是一回事!这意味着我们正在使用它this->B<T>作为限定符,并且它毕竟不是一个小问题

在另一种情况下,

this->bitset
Run Code Online (Sandbox Code Playgroud)

进行相同的,直到第三步,当它意识到有两个不同的东西叫做bitset(模板类成员和类模板),只是放弃.


这是来自我躺着的工作草案,所以不一定是最近的,但是:

3.4.5类成员访问[basic.lookup.classref]

1在类成员访问表达式(5.2.5)中,如果是.或 - > token后面紧跟一个标识符后跟一个<,必须查找标识符以确定<是模板参数列表(14.2)的开头还是小于运算符.首先在对象表达式的类中查找标识符.如果未找到标识符,则在整个postfix-expression的上下文中查找它,并命名一个类模板.如果对象表达式的类中的查找找到模板,则还会在整个后缀表达式的上下文中查找该名称,

  • 如果找不到名称,则使用在对象表达式的类中找到的名称,否则使用
  • 如果在整个postfix-expression的上下文中找到该名称并且未命名类模板,则使用在对象表达式的类中找到的名称,否则
  • 如果找到的名称是类模板,则它应该引用与在对象表达式的类中找到的实体相同的实体,否则程序是不正确的.

因此,在任何表达式中this->id < ...,它必须处理id<...模板标识符的开头(例如this->B<T>::bitset).

它仍然首先检查对象,但如果this->id找到模板,则应用进一步的步骤.在你的情况下,this->bitset可能被认为是一个模板,因为它仍然依赖T,所以它发现冲突,std::bitset并在上面的第三个子弹失败.

  • 谢谢,我得说这是我在C++代码中见过的最模糊的错误之一. (3认同)