"端"不能在模板功能中使用

时间:2015-07-29 03:51:09

标签: 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;
}

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

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

4 个答案:

答案 0 :(得分:9)

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

  

当成员模板专业化的名称出现之后。或 - &gt;在后缀表达式中或之后    qualified-id 中的 nested-name-specifier postfix-expression 的对象表达式类型相关   或 qualified-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
}
     

-end example]

v1v2类型相关的,因此,由于省略了template关键字,因此应该假定名称命名非模板<应该被视为小于,完全如上例所示。

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

  

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

并且end应该清楚地在对象表达式的类中找到 - 毕竟它是一个简单的成员变量。 end仅因为与std::end()的冲突导致失败的事实进一步支持了bug的概念,因为该范围永远不会被认为是开始的。

有趣的是,最简单的解决方案就是:don't use using namespace std;

答案 1 :(得分:8)

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

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

  

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

     

&#34;在类成员访问表达式(5.2.5)中,如果.->令牌是   紧接着是一个标识符,后跟一个&lt ;,标识符   必须抬头确定是否&lt;是一个开始   模板参数列表(14.2)或小于运算符。标识符   首先在对象表达式的类中查找。如果   找不到标识符,然后在上下文中查找   整个postfix-expression并命名一个类模板。&#34;

     

由于v是依赖的,可能是找不到标识符所以我们   考虑如果我们查看整个环境会发生什么   后缀表达式。由于我们找到了一个函数模板,我们不应该   得出结论,我们有一个模板ID的开头。

来源:C++ confusing attribute name for member template

以下是相应的gcc错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=10200

  

* 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);
  

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

     

这应该尽快修复,但我没有积极处理它   时刻。

答案 2 :(得分: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;
};

答案 3 :(得分: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;
}