operator+
   
   举个例子)。
  
  struct B{};
template<class>
struct A{
    template<class BB>
    void operator+(BB const&) const{std::cout<<"member"<<std::endl;}
    template<class BB>
    friend void operator+(BB const&, A const&){std::cout<<"friend"<<std::endl;}
};
  
   我可以用两种不同的类型来调用这个二进制运算符:
  
  A<int> a;
B b;
a + b; // member
b + a; // friend
  
   当我尝试使用
   
    A
   
   两边(
   
    a + a
   
   )很多奇怪的事情发生了。三个编译器对同一代码给出不同的答案。
  
  
   一些背景:我不想定义
   
    void operator+(A const&)
   
   
    template<class BB, class AA> friend void operator(BB const&, AA const&)
   
   . 因为自从
   
    A
   
  
  
   继续原始代码:
  
  
   
    奇怪的事情#1:
   
  
  a + a; // prints friend in gcc
  
   我希望成员优先,
   
    有没有办法让成员优先?
   
  
  
   
    奇怪的事情2:
   
   在clang中,此代码不编译:
  
  a + a; // use of overload is ambiguous
  
   
   
   
   
  
  
   如果我试图在参数上更加贪婪,例如应用一些优化,我可以使用转发引用:
  
  struct A{
    template<class BB>
    void operator+(BB&&) const{std::cout<<"member"<<std::endl;}
    template<class BB>
    friend void operator+(BB&&, A const&){std::cout<<"friend"<<std::endl;}
};
  
   
    奇怪的事情3:
   
  
  a + a; // print "friend", but gives "warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:"
  
   但仍然编译,
   
   
   就像案例1一样,我希望更喜欢成员函数,但这里它更喜欢朋友函数
   
   
   发出警告。
  
  
   
    怪事四:
   
  
  a + a; // error: use of overloaded operator '+' is ambiguous (with operand types 'A' and 'A')
  
   这再次指出了gcc和clang之间的不一致性,在这个案例中谁是对的?
  
  
   总而言之,我正在努力使这段代码始终如一地工作。我真的希望这个函数是注入的朋友函数(不是免费的朋友函数)。我不想用相等的非模板参数定义函数,因为不同的实例化将产生相同函数的重复声明。
  
  
  
  
  #include<iostream>
using std::cout;
struct B{};
template<class>
struct A{
    template<class BB>
    void operator+(BB const& /*or BB&&*/) const{cout<<"member\n";}
    template<class BB>
    friend void operator+(BB const& /*or BB const&*/, A const&){cout<<"friend\n";}
};
int main(){
    A<int> a;      //previos version of the question had a typo here: A a;
    B b;
    a + b; // calls member
    b + a; // class friend
    a + a; // surprising result (friend) or warning in gcc, hard error in clang, MSVC gives `member` (see below)
    A<double> a2; // just to instantiate another template
}
  
  
   注意:我正在使用
   
    clang version 6.0.1
   
   和
   
    g++ (GCC) 8.1.1 20180712
   
   . 根据Francis Cugler MSVS 2017,CE给出了一个不同的行为。
  
  
  
   我找到了一个解决方法,可以做正确的事情(为
   
    a+a
   
   对于clang和gcc(对于MSV?),但对于boiler plate和人工基类需要大量的数据:
  
  template<class T>
struct A_base{
    template<class BB>
    friend void operator+(BB const&, A_base<T> const&){std::cout<<"friend"<<std::endl;}
};
template<class T>
struct A : A_base<T>{
    template<class BB>
    void operator+(BB const&) const{std::cout<<"member"<<std::endl;}
};
  
   但是,如果我替换它,它仍然会给出一个模棱两可的调用
   
    BB const&
   
   
    BB&&
   
   .