pretzlstyle
pretzlstyle

Reputation: 2962

Template function broken after compiling with C++11

I have a very simple template function to compare the rank field of two structs:

template<typename T>
bool comp_rank(const T &a, const T &b){
    return a.rank < b.rank;
}

This worked fine, until I compiled with -std=c++11. Now, I get the error

error: parameter "b" is not a type name
      return a.rank < b.rank;
                      ^

./src/util.h(123): error: expected a ">"
      return a.rank < b.rank;
                       ^

What gives? This seems like basic syntax that I would surprised to find had changed after C++11.

Upvotes: 3

Views: 161

Answers (3)

Jans
Jans

Reputation: 11250

This is an issue that CGW 1835 deal with, citing it here:

According to 6.4.5 [basic.lookup.classref] paragraph

In a class member access expression (8.2.5 [expr.ref]), if the . or -> token is immediately followed by an identifier followed by a <, the identifier must be looked up to determine whether the < is the beginning of a template argument list (17.2 [temp.names]) or a less-than operator. 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.

template<typename T> T end(T);
template<typename T>
bool Foo(T it) {
    return it->end < it->end;
}

since it is dependent and thus end cannot be looked up in the class of the object expression, it is looked up in the context of the postfix-expression. This lookup finds the function template, making the expression ill-formed.

One possibility might be to limit the lookup to the class of the object expression when the object expression is dependent.


#include <type_traits>

using namespace std;

template<typename T>
bool comp_rank(const T &a, const T &b){
    return a.rank < b.rank; // fail
}

The error shows up even without instantiating the function template, the whole expression is dependent, hence they can't be looked up into the class scope. As the current wording of the standard is not clear if lookup for rank in the class scope will be deferred for dependent names or must be bound to names in the context of the postfix-expression that's what the CGW try to tackle.

a direct solution is to use parens:

template<typename T>
bool comp_rank(const T &a, const T &b){
    return (a.rank) < (b.rank);
}

Upvotes: 3

AndyG
AndyG

Reputation: 41100

Edit: I've submitted a bug report to gcc here. It's currently unconfirmed.

Given that you accepted @Klaus' answer, your code looks something like this (thanks @krzaq):

#include <type_traits>

using namespace std;

struct A{ int rank; };

template<typename T>
bool comp_rank(const T &a, const T &b){
    return a.rank < b.rank;
}

int main()
{
    A a{42}, b{0};
    comp_rank(a, b);
}

Both gcc (9.0.0 and earlier were tested), and clang (8.0.0 and earlier were tested) reject this code on the grounds that they are expecting the id-expression a.rank< to be the start of a template. According to the standard, this is the wrong interpretation. See [basic.lookup.classref]

In a class member access expression, if the . or -> token is immediately followed by an identifier followed by a <, the identifier must be looked up to determine whether the < is the beginning of a template argument list or a less-than operator. 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.

The compiler should have looked up a.rank and discovered it to be an integer member of class A. MSVC 19.00.23506 compiles it just fine

Upvotes: 7

Klaus
Klaus

Reputation: 25613

Your problem is that you use

using namespace std;

Because c++11 introduces a template rank

See here : https://en.cppreference.com/w/cpp/types/rank

If you remove the using statement, everything compiles fine again!

Here is the error message given by gcc 8.2.1

main.cpp: In function 'bool comp_rank(const T&, const T&)':
main.cpp:41:23: error: type/value mismatch at argument 1 in template parameter list for 'template<class> struct std::rank'
    return a.rank < b.rank;

It is not a good idea to use using namespace ... anyway. You gave already a good example ;)

Upvotes: 5

Related Questions