类内声明的友元运算符中左手参数的隐式转换

2024-01-03

我正在使用 CRTP 向类提供依赖于模板参数的函数添加,在本例中添加operator + and operator +=,使用模板类ImplAdd。对于前者,应该对两个参数执行隐式转换,这意味着我必须使用类内友元运算符,如下所示:

template<class Type, bool active>
struct ImplAdd{
    virtual int get_val_() const = 0;
    virtual void set_val_(int) = 0;
};

//if activated is true, the operators + and += will be defined
template<class Type>
class ImplAdd < Type, true > {
    virtual int get_val_() const = 0;
    virtual void set_val_(int) = 0;
    Type* this_(){ return (Type*)this; }
public:
    Type& operator +=(const Type& x){
        set_val_(get_val_() + x.get_val_());
        return *this_();
    }

    //This should enable conversions on the lefthand argument
    friend Type& operator+(const Type& lhs, const Type& rhs){
        Type ret = lhs;
        return ret += rhs;
    }
};

这是必需的,因为实际继承自的类ImplAdd定义常量值和这些常量的唯一值类型,就像作用域枚举一样。

//by using true as the template argument, the operators + and += will be defined
class MyEnum : public ImplAdd<MyEnum, true>{
    int get_val_() const override{
        return (int)value;
    }
    void set_val_(int v) override{
        value = (ValueT)v;
    }
public:
    enum class ValueT{
        zero, one, two
    };
private:
    typedef  int UnderlyingT;
    ValueT value;
public:
    static const ValueT zero = ValueT::zero;
    static const ValueT one = ValueT::one;
    static const ValueT two = ValueT::two;
    MyEnum(ValueT x) : value(x){}
    MyEnum(const MyEnum& other) : value(other.value){}
};

从我的角度来看,以下代码现在应该可以轻松编译,但事实并非如此。

int main(int argc, char* argv[])
{
    MyEnum my = MyEnum::zero;                //works
    my += MyEnum::one;                       //works
    my = MyEnum(MyEnum::zero) + MyEnum::two; //works
    my = MyEnum::zero + MyEnum(MyEnum::two); //ERROR C2676
    my = MyEnum::zero + MyEnum::two;         //ERROR C2676
    MyEnum my2 = my + my;                    //works
    return 0;
}

对于标有 C2676 的两行,将打印以下错误消息:

error C2676: binary '+' : 'const MyEnum::ValueT' does not define this operator or a conversion to a type acceptable to the predefined operator

我究竟做错了什么?使用将运算符定义为类内友元不是在两个参数上启用隐式转换的常见方法吗?如果没有的话,在这种情况下我该怎么办?


§13.3.1.2 [over.match.oper]/p3(添加强调):

对于二元运算符@其左操作数的类型 简历不合格版本是T1和一个类型的右操作数 简历不合格版本是T2,三组候选函数, 指定的会员候选人, 非会员候选人 and 内置 候选人,构造如下:

  • [...]
  • 非成员候选集是无条件查找的结果operator@在表达式的上下文中根据 非限定函数调用中名称查找的常用规则 (3.4.2) 除了忽略所有成员函数之外。但是,如果没有操作数 具有类类型,仅查找集中的那些非成员函数 第一个参数类型为T1或“参考(可能 简历合格)T1”,当T1是枚举类型,或者(如果有 右操作数)类型的第二个参数T2或“参考 (可能符合简历要求)T2”, when T2是一个枚举类型,有 候选函数。
  • [...]

用更简单的英语来说,如果两个操作数都没有类类型,那么您需要在枚举操作数上进行精确匹配才能考虑重载,这就是为什么my = MyEnum::zero + MyEnum::two;不起作用。my = MyEnum::zero + MyEnum(MyEnum::two);奇怪的是,它可以在 GCC 中编译,但不能在 Clang 中编译。我找不到任何使它不合法的东西,所以我怀疑这可能是一个编译器错误。

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

类内声明的友元运算符中左手参数的隐式转换 的相关文章

  • 在 C++ 中使用 matlab 结构(matlab 函数调用的返回值)(由 matlab 编译器生成的库)

    你好 我有一个相当简单的 matlab 函数 例如 function MYSTRUCT myfunc MYSTRUCT prop1 test MYSTRUCT prop2 foo MYSTRUCT prop3 42 end 我用 matla
  • 如何让 Swagger 插件在自托管服务堆栈中工作

    我已经用 github 上提供的示例重新提出了这个问题 并为任何想要自己运行代码的人提供了一个下拉框下载链接 Swagger 无法在自托管 ServiceStack 服务上工作 https stackoverflow com questio
  • 如何将非静态类成员“std::bind”绑定到 Win32 回调函数“WNDPROC”?

    我正在尝试将非静态类成员绑定到标准WNDPROC http msdn microsoft com en us library ms633573 aspx功能 我知道我可以通过将类成员设为静态来简单地做到这一点 但是 作为一名 C 11 ST
  • 错误:表达式不产生值

    我尝试将以下 C 代码转换为 VB NET 但在编译代码时出现 表达式不产生值 错误 C Code return Fluently Configure Mappings m gt m FluentMappings AddFromAssemb
  • 复制目录内容

    我想将目录 tmp1 的内容复制到另一个目录 tmp2 tmp1 可能包含文件和其他目录 我想使用C C 复制tmp1的内容 包括模式 如果 tmp1 包含目录树 我想递归复制它们 最简单的解决方案是什么 我找到了一个解决方案来打开目录并读
  • 单个对象的 Monogame XNA 变换矩阵?

    我读过一些解释 XNA Monogame 变换矩阵的教程 问题是这些矩阵应用于 SpriteBatch Begin matrix 这意味着所有 Draw 代码都将被转换 如何将变换矩阵应用于单个可绘制对象 就我而言 我想转换滚动背景 使其自
  • 获取两个工作日之间的天数差异

    这听起来很简单 但我不明白其中的意义 那么获取两次之间的天数的最简单方法是什么DayOfWeeks当第一个是起点时 如果下一个工作日较早 则应考虑在下周 The DayOfWeek 枚举 http 20 20 5B1 5D 3a 20htt
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • 为什么 Google 测试会出现段错误?

    我是 Google Test 的新手 正在尝试提供的示例 我的问题是 当我引入失败并设置GTEST BREAK ON FAILURE 1 或使用命令行选项 GTest 将出现段错误 我正在考虑这个例子 https code google c
  • 由 IHttpClientFactory 注入时模拟 HttpClient 处理程序

    我创建了一个自定义库 它会自动为依赖于特定服务的 Polly 策略设置HttpClient 这是使用以下方法完成的IServiceCollection扩展方法和类型化客户端方法 一个简化的例子 public static IHttpClie
  • qdbusxml2cpp 未知类型

    在使用 qdbusxml2cpp 程序将以下 xml 转换为 Qt 类时 我收到此错误 qdbusxml2cpp c ObjectManager a ObjectManager ObjectManager cpp xml object ma
  • 在一个平台上,对于所有数据类型,所有数据指针的大小是否相同? [复制]

    这个问题在这里已经有答案了 Are char int long 甚至long long 大小相同 在给定平台上 不能保证它们的大小相同 尽管在我有使用经验的平台上它们通常是相同的 C 2011 在线草稿 http www open std
  • 如何检测表单的任何控件的变化?

    如何检测 C 中表单的任何控件的更改 由于我在一个表单上有许多控件 并且如果表单中的任何控件值发生更改 我需要禁用按钮 我正在寻找一些内置函数 事件处理程序 属性 并且不想为此创建自定义函数 不 我不知道任何时候都会触发任何事件any控制表
  • Qt - ubuntu中的串口名称

    我在 Ubuntu 上查找串行端口名称时遇到问题 如您所知 为了在 Windows 上读取串口 我们可以使用以下代码 serial gt setPortName com3 但是当我在 Ubuntu 上编译这段代码时 我无法使用这段代码 se
  • 如何在 Xaml 文本中添加电子邮件链接?

    我在 Windows Phone 8 应用程序中有一些大文本 我希望其中有电子邮件链接 例如 mailto 功能 这是代码的一部分
  • C# HashSet 只读解决方法

    这是示例代码 static class Store private static List
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • Oracle Data Provider for .NET 不支持 Oracle 19.0.48.0.0

    我们刚刚升级到 Oracle 19c 19 3 0 所有应用程序都停止工作并出现以下错误消息 Oracle Data Provider for NET 不支持 Oracle 19 0 48 0 0 我将 Oracle ManagedData
  • 如何从 ODBC 连接获取可用表的列表?

    在 Excel 中 我可以转到 数据 gt 导入外部数据 gt 导入数据 然后选择要使用的数据源 然后在提供登录信息后 它会给我一个表格列表 我想知道如何使用 C 以编程方式获取该列表 您正在查询什么类型的数据源 SQL 服务器 使用权 看
  • 从列表中选择项目以求和

    我有一个包含数值的项目列表 我需要使用这些项目求和 我需要你的帮助来构建这样的算法 下面是一个用 C 编写的示例 描述了我的问题 int sum 21 List

随机推荐