“end”不能在模板函数中使用。

10

我想在一个函数模板中使用一个简单的结构体,该结构体具有名为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;
}

但是这个程序在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)
     ^

为什么不行?我的代码有什么问题吗?

确切的错误信息是什么?顺便说一下,测试类型在任何地方都没有定义。 - billz
  1. 应该删除“测试测试”这一行,我忘记了。我想要一个小代码来阅读。
  2. 错误信息是:test.cpp: 在成员函数 'void compare(const T&, const T&)' 中: test.cpp:14:15: 错误:模板参数列表中的解析错误 如果(v1.end < v2.end)
- xiao
4个回答

10

这显然是gcc的一个bug(具体来说是10200,尽管有几个重复的例子)。 [temp.names]中指出:

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template. [ Example:

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
}

—end example ]

v1v2类型相关的,因此由于省略了template关键字,应该假定名称指向非模板,并且<应该像上面的示例一样被视为小于号。

更不用说[basic.lookup.classref]规定:

首先在对象表达式的类中查找标识符。如果未找到标识符,则在整个后缀表达式的上下文中查找,并应命名类模板。

end显然应该在对象表达式的类中找到——毕竟它只是一个简单的成员变量。事实上,由于与std::end()的冲突导致end失败,进一步支持了bug的想法,因为那个作用域本来就不应该被考虑。

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


8
实际上是< 搞混了编译器,因为它不知道它是模板表达式的开始还是比较运算符的开始。
由于@R Sahu要求官方来源,这里是解释:
"在类成员访问表达式(5.2.5)中,如果.->标记紧随其后,紧跟着一个标识符和<,则必须查找标识符以确定<是模板参数列表(14.2)的开始还是小于运算符的开始。首先在对象表达式的类中查找标识符。如果未找到标识符,则在整个后缀表达式的上下文中查找,并且应命名类模板。"
由于v是相关的,假设未找到标识符,因此我们考虑在整个后缀表达式的上下文中查找会发生什么。由于我们找到一个函数模板,我们不应该得出我们有一个模板ID的开头。
来源:C++ confusing attribute name for member template 以下是相应的gcc bug:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=10200
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);

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

这个问题需要尽快解决,但目前我并没有积极处理它。


0

我认为,暂时你可以反向检查条件。

#include <iostream>
using namespace std;

struct st {
    int start;
    int end;
};

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

int main() {
    st a = {1, 2};
    st b = {2, 3};
    compare(a, b);
    return 0;
}

0

看起来,当成员变量为 beginend 时, g++ 4.8.4 也会出现问题。

使用:

struct st{
    int begin;
    int end;
};

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

这个问题会对我产生以下错误信息。

socc.cc: In function ‘void compare(const T&, const T&)’:
socc.cc:12:11: error: parse error in template argument list
     if(v1.begin < v2.begin)
           ^
socc.cc:16:11: error: parse error in template argument list
     if(v1.end < v2.end)
           ^
socc.cc: In instantiation of ‘void compare(const T&, const T&) [with T = st]’:
socc.cc:25:17:   required from here
socc.cc:12:5: error: ‘begin’ is not a member template function
     if(v1.begin < v2.begin)
     ^
socc.cc:16:5: error: ‘end’ is not a member template function
     if(v1.end < v2.end)

也许比我更熟悉g++开发的人可以提供更多细节。
一个解决方法是避免使用beginend作为成员变量。
struct st{
    int _begin;
    int _end;
};

或者

struct st{
    int _start;
    int _end;
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接