Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"end" cannot use in template function

Tags:

c++

templates

I want to use a simple struct with member variables named start and end in a function template:

#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;
}

But this program fails to compile on mingw g++ 4.8.2 with:

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)
     ^

Why not? What's wrong with my code?

like image 551
xiao Avatar asked Jul 29 '15 03:07

xiao


1 Answers

This is clearly a gcc bug (specifically 10200 although there are several dupes with lots of different examples). [temp.names] states:

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 ]

v1 and v2 are type-dependent, so the name should be assumed to name a non-template due to the omitted template keyword and the < should be treated as less than, exactly as in the example above.

Not to mention that [basic.lookup.classref] states that:

The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template.

And end should clearly be found in the class of the object expression - it's a simple member variable, after all. The fact that it's a failure for end only because of the collision with std::end() further supports the idea of bug since that scope should never have been considered to begin with.

Amusingly, the simplest solution is simply: don't use using namespace std;!

like image 174
Barry Avatar answered Sep 16 '22 15:09

Barry