友元和成员二元运算符的消歧

2023-12-11

考虑以下带有二元运算符的类(我使用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 中,友元优先:

a + a; // prints friend in gcc

我希望会员优先,有没有办法让成员优先于 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 一样,我希望更喜欢成员函数,但这里更喜欢友元函数and发出警告。

奇怪的事情#4:使用转发引用会导致 clang 错误。

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 and g++ (GCC) 8.1.1 20180712。根据 Francis Cugler MSVS 2017 CE 的说法,CE 给出了不同的行为。


我找到了一种解决方法,可以做正确的事情(打印“成员”a+acase)对于 clang 和 gcc (对于 MSVS?),但它需要大量的样板和人工基类:

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& with BB&&.


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

只要限制你的朋友不参与重载决议,如果BB是一个专业化A.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

友元和成员二元运算符的消歧 的相关文章

随机推荐

  • 如何在 JavaScript 中按下按键时播放声音?

    我正在尝试编写 JavaScript 代码 以便仅在按下某个键时才播放声音 我试图将其关联的 HTML 代码是 div class key div
  • Kivy - python - 回收视图行中的多个小部件

    我想制作一个在每个回收视图行中有多个标签的回收视图 在我的具体示例中 我希望每行有 3 个标签 1 个包含项目索引的标签 一个包含一个数据集中的项目的标签 以及另一个数据集中的另一个标签 在此示例中 取自 kivy 示例 我们有一个回收视图
  • 解压 tar.gz 文件? [复制]

    这个问题在这里已经有答案了 我想下载并打开以下内容tar gzR 中的文件 http s wordpress org resources survey wp2011 survey tar gz 有没有一个命令可以完成这个任务 fn lt h
  • 如何准备包含 NText (clob) 参数的 ADO.NET 语句

    我正在更新一个现有的应用程序 该应用程序使用工厂来构建准备好的语句 然后稍后执行它们 这适用于系统的其余部分 但我的任务是添加对使用NText 我不知道如何正确准备声明 我收到以下运行时错误 SqlCommand Prepare 方法要求所
  • 将 HTML 5 文档类型添加到 XDocument (.NET)

    为 System Xml Linq XDocument 创建文档类型时 如下所示 doc AddFirst new XDocumentType html null null null 生成的保存的 XML 文件开头为 请注意右尖括号之前的额
  • 从指针指向内存的二进制文件读取结构

    struct st char p int len 这是我需要写入二进制文件的结构 以及保存在中的字符串 char p 我应该用字符数组数据编写一个二进制文件 写入二进制文件后 还应该能够从二进制文件中以相同的结构读取它 我尝试使用 FSEE
  • 单击和双击事件触发

    我正在使用 jQuery 编写事件处理程序 并且有一个关于单击和双击事件的问题 我有一个带有 文件 类的元素 它附加了两个事件处理程序 一个用于单击元素 另一个用于双击 我希望两者独立触发 但似乎当双击事件触发时 单击事件总是触发 file
  • iframe 上的点击事件?

    我有一个简单的 iFrame 我知道我无法捕获框架内元素上的单击事件 但是在 iFrame 本身上进行简单的单击或鼠标按下怎么样 inviteFrame click function console log test this attr h
  • 分块读取 20GB 文件而不超出我的 RAM - R

    我目前正在尝试读取 20GB 的文件 我只需要该文件的 3 列 我的问题是 我的内存限制为 16 GB 我尝试使用readr并使用该函数以块的形式处理数据read csv chunked and read csv使用skip参数 但它们都超
  • Android 中的自定义 pdf 查看器

    我需要在我的应用程序中有一个自定义的 pdf 查看器 其中我有自己的菜单和所有内容 它不适用于 webview 我尝试将每个页面转换为图像 但我觉得这不是一个好方法 它使我的应用程序变得又大又复杂 有什么方法可以创建自定义 pdf 视图 建
  • 在 JBoss AS 7.1.X 上使用带有 Spring 3.0.X 的 JAX-WS Web 服务

    我在 JBoss AS Final 7 1 1 上使用 Spring 3 0 6 部署 JAX WS Web 服务时遇到一些问题 我尝试了本教程中的两种第一种方法 http www javacodegeeks com 2010 11 jax
  • 如何隐藏页面内容,直到所有图像完全加载?

    我正在尝试优化一个负载严重的网站 我已经重新排序 压缩和缩小了 js 和 css 但最大的问题是图像 该网站包含一些非常重的图像 因此当它开始加载时 内容会在所有图像加载时跳转 我无法手动设置包含图像的 div 的高度 因为它们是用户提交的
  • iPhone 系列设置后,应用商店中的应用程序是否支持 iPad?

    我在 App Store 上有一个应用程序 并且我已多次确保在以下位置选择 iPhone 应用程序 gt 目标 gt 常规 gt 部署信息 gt 设备 gt iPhone 而不是通用或iPad 每次应用程序获得批准时 它仍然显示 支持 iP
  • selenium.common.exceptions.SessionNotCreatedException:消息:无法找到与 GeckoDriver、Selenium 和 Firefox 匹配的功能集

    我用 selenium 和 firefox webdriver 开发了一个 python 脚本 它在我的机器上运行良好 但如果我在另一台机器上执行相同的脚本 则会出现以下错误 Traceback most recent call last
  • ValueError:值必须是周期、字符串、整数或日期时间

    我在使用日期时间时遇到问题 我有一个带有列时间的数据框 print dt time dtypes 它回复 datetime64 ns 现在我想要得到该日期所在月份的天数 dt NB DAYS p Period dt time days in
  • Ajax刷新后如何绑定jQuery Datepicker?

    我有一个 jQuery 日期选择器 它对我来说非常有用 除了当我通过 ajax 刷新内容时 我丢失了日期选择器 据我所知我应该使用 jQueryon 将其绑定到输入 但我似乎找不到将其绑定到的正确事件 第一次有效 但后续刷新时无效 id s
  • Git 在分支之前拆分提交

    假设您有以下历史 D G feature1 1 A B C E F feature1 现在我想将 B 分成两个提交以获得 D G feature1 1 A B1 B2 C E F feature1 你不能只执行 git rebase i 然
  • 将嵌套列表转换为列表[重复]

    这个问题在这里已经有答案了 我有一个简短的问题 我想取消这个嵌套列表的嵌套 mylist lt list a list A 1 B 5 b list C 1 D 2 c list E 1 F 3 预期结果是 gt list a c 1 5
  • JavaFX FXML 参数从控制器 A 传递到 B 并返回

    我想创建一个基于 JavaFX GUI 的控制器 由多个控制器组成 我无法完成的任务是将参数从一个场景传递到另一个场景并返回 或者换句话说 MainController加载SubController的fxml 将对象传递给SubContro
  • 友元和成员二元运算符的消歧

    考虑以下带有二元运算符的类 我使用operator 仅作为示例 struct B template