gpt4 book ai didi

c++ - friend 和成员二元运算符的消歧

转载 作者:行者123 更新时间:2023-12-03 06:50:22 25 4
gpt4 key购买 nike

考虑以下带有二元运算符的类(我使用 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&)因为如果某些语法不起作用,我需要一个模板来 SFINAE 函数。我也不想要 template<class BB, class AA> friend void operator(BB const&, AA const&) .因为自从 A是一个模板,不同的实例化会产生同一个模板的多个定义。

继续原始代码:

奇怪的事情#1:在 gcc 中, friend 优先:
a + a; // prints friend in gcc

我希望成员(member)优先, 有没有办法让成员(member)优先 gcc?

奇怪的事情#2:在 clang 中,此代码无法编译:
a + a; // use of overload is ambiguous

这已经指出了 gcc 和 clang 之间的不一致, 谁是对的? 让clang像gcc一样工作的解决方法是什么?

如果我试图在争论中更加贪婪,例如要应用一些优化,我可以使用转发引用:
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:使用转发引用会在 gcc 中发出警告,
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:"

但仍然编译, 如何在 gcc 或解决方法中消除此警告? 就像案例 #1 一样,我希望更喜欢成员函数,但在这里它更喜欢 friend 函数并给出警告。

奇怪的事情#4:使用转发引用会在 clang 中产生错误。
a + a; // error: use of overloaded operator '+' is ambiguous (with operand types 'A' and 'A')

这再次指出 gcc 和 clang 之间的不一致,在这种情况下谁是对的?

总之,我试图让这段代码始终如一地工作。我真的希望该功能被注入(inject) friend 功能(不是免费的 friend 功能)。我不想定义具有相同非模板参数的函数,因为不同的实例化会产生相同函数的重复声明。

这是完整的代码:
#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.1g++ (GCC) 8.1.1 20180712 .根据 Francis Cugler 的说法,MSVS 2017 CE 给出了不同的行为。

我找到了一种解决方法,可以为 clang 和 gcc(对于 MSVS?)执行正确的操作(为 a+a 案例打印“成员”),但它需要大量样板和人工基类:
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&& .

最佳答案

这些都是模棱两可的。在对成员和非成员进行排序时,GCC 中存在已知的部分排序错误,例如https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66914 .

如果 BB,请限制您的 friend 不要参与重载决议是 A 的特化.

关于c++ - friend 和成员二元运算符的消歧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64681996/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com