Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC and Clang template call resolution differences

Given the following code:

#include <iostream>

struct Alice
{
  template <typename A>
  void operator|(const A& /*a*/) const
  {
    std::cout << "operator| member" << std::endl;
  }
};

template <typename A>
void operator|(const A& /*a*/, const Alice& /*alice*/)
{
  std::cout << "operator| non-member" << std::endl;
}

int main()
{
  Alice a;
  Alice b;

  a | b;

  return 0;
}

It compiles without warning with both GCC 4.8.1, 4.9 and clang 3.4, but gives different results.

$ g++ -Wall -Wextra -std=c++11 alice.cpp && ./a.out
operator| non-member

$ clang++ -Wall -Wextra -std=c++11 alice.cpp && ./a.out
operator| member

What causes this difference? How can I force the same behaviour?

EDIT: Interesting fact: removing the const qualifier from the member function makes gcc prefer the member function also. It does not solve the problem, however.

EDIT: clang++ prefers the non-member instead, if -std=c++11 is not specified.

EDIT: ICC 14.0 prefers non-member, no warning emitted.

like image 951
erenon Avatar asked May 22 '14 19:05

erenon


1 Answers

According to overload resolution, there are two viable functions: The specialization of the global operator|-template with deduced arguments and the specialization of the member operator function template. Both have the same signature - the member function template has an implicit object parameter of type Alice const& (see §13.3.1/4).

So both viable functions (after template argument deduction) have the same signature. And neither of the templates from which they were instantiated is more specialized than the other. So this is indeed an ambiguity and therefore ill-formed. Surprisingly, VC++ is correct.

How can I force the same behaviour?

Perhaps you should just remove the ambiguity, Clang, VC++ and GCC should have the same behavior then.

like image 190
Columbo Avatar answered Sep 20 '22 03:09

Columbo