GCC和Clang模板调用解析差异

时间:2014-05-22 19:32:12

标签: c++ gcc clang language-lawyer

给出以下代码:

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

它在没有警告的情况下编译GCC 4.8.1,4.9和clang 3.4,但会得到不同的结果。

$ 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

造成这种差异的原因是什么?我怎么能强迫同样的行为?

编辑:有趣的事实:从成员函数中删除const限定符会使gcc更喜欢成员函数。但是,它并没有解决问题。

编辑:如果未指定-std=c++11,则clang ++更喜欢非会员。

编辑: ICC 14.0更喜欢非会员,不会发出任何警告。

1 个答案:

答案 0 :(得分:8)

根据重载决策,有两个可行的函数:全局operator|的特化 - 带有推导参数的模板和成员操作符函数模板的特化。两者都具有相同的签名 - 成员函数模板具有类型为Alice const&的隐式对象参数(参见§13.3.1/ 4)。

因此两个可行的函数(在模板参数推导之后)具有相同的签名。并且它们实例化的模板都不比另一个模板更专业。所以这确实是一种含糊不清,因此形成不良。令人惊讶的是,VC ++是正确的。

  

我如何强制执行相同的行为?

也许你应该删除歧义,Clang,VC ++和GCC应该有相同的行为。