"结束"不能用于模板功能

xia*_*iao 9 c++ templates

我想在命令startend函数模板中使用一个带有成员变量的简单结构:

#include <iostream>
using namespace std;

struct st {
    int start;
    int end;
};

template<typename T>
void compare(const T& v1, const T& v2){
    if(v1.end < v2.end)
        cout << "v1 < v2" << endl;
}

int main() {
    st a = {1, 2};
    st b = {2, 3};
    compare(a, b);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是这个程序无法在mingw g ++ 4.8.2上编译:

main.cpp: In function 'void compare(const T&, const T&)':
main.cpp:11:11: error: parse error in template argument list
     if(v1.end < v2.end)
           ^
main.cpp: In instantiation of 'void compare(const T&, const T&) [with T = st]':
main.cpp:18:17:   required from here
main.cpp:11:5: error: 'end' is not a member template function
     if(v1.end < v2.end)
     ^
Run Code Online (Sandbox Code Playgroud)

为什么不?我的代码出了什么问题?

Bar*_*rry 9

这显然是一个gcc bug(特别是10200,尽管有几个dupes有很多不同的例子).[temp.names]声明:

当成员模板专业化的名称出现之后.或-在一个> 后缀表达式或一后 嵌套名称说明符在一个合格-ID,和对象表达后缀表达式类型相关嵌套名称说明符合格-ID是指,以一个依赖类型,但名称不是当前实例化的成员(14.6.2.1),成员模板名称必须以关键字为前缀template. 否则,假定该名称命名非模板. [例如:

struct X {
    template<std::size_t> X* alloc();
    template<std::size_t> static X* adjust();
};

template<class T> void f(T* p) {
    T* p1 = p->alloc<200>();          // ill-formed: < means less than
    T* p2 = p->template alloc<200>(); // OK: < starts template argument list
    T::adjust<100>();                 // ill-formed: < means less than
    T::template adjust<100>();        // OK: < starts template argument list
}
Run Code Online (Sandbox Code Playgroud)

- 末端的例子]

v1并且v2类型相关的,因此应该假定名称由于省略的template关键字而命名非模板,并且<应该将其视为小于,与上面的示例完全相同.

更不用说[basic.lookup.classref]声明:

首先在对象表达式的类中查找标识符.如果未找到标识符,则在整个postfix-expression的上下文中查找它,并命名一个类模板.

并且end应该清楚地在对象表达式的类中找到 - 毕竟它是一个简单的成员变量.它end只是因为碰撞而失败的事实std::end()进一步支持了bug的想法,因为该范围永远不应该被认为是开始的.

有趣的是,最简单的解决方案就是:不要使用using namespace std;!


luc*_*asg 8

实际上,它<会混淆编译器,因为它不知道它是模板表达式的开始还是比较器.

由于@R Sahu要求官方消息来源,以下是解释:

这里重要的段落是[basic.lookup.classref] p1:

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

由于v是依赖的,可能是找不到标识符所以我们考虑如果我们查看整个postfix-expression的上下文会发生什么.由于我们找到了一个函数模板,因此我们不应该断定我们有一个模板ID的开头.

来源:C++令人困惑的成员模板属性名称

这是相应的gcc错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id = 010200

*Paolo Carlini 2015-06-23 15:03:03 UTC*

错误65878已被标记为此错误的副本.

*Colin MacKenzie 2015-06-23 22:19:29 UTC*

今天有这个.奇怪的是它在4.4.6中编译得很好但在4.8.2中没编译.

error: parse error in template argument list 
Ex: assert(block.begin <  block.end);

works when I parenthesize the block.begin 
Ex. assert( (block.begin) < block.end);
Run Code Online (Sandbox Code Playgroud)

*Paolo Carlini 2015-06-23 22:21:28 UTC*

这应该尽快修复,但我现在还没有积极地处理它.