【问题标题】:In C++11, how can I implement an arithmetic type that fits into the hierarchy of builtin types?在 C++11 中,如何实现适合内置类型层次结构的算术类型?
【发布时间】:2015-06-21 12:26:17
【问题描述】:

基本上,我想实现一个float16 类型。但这个问题不是关于如何做到这一点的细节,而是关于如何设置,以便我的新 float16 类型与 float、double 和所有整数类型表现得恰当。

我希望我的float16 类型可以类似地转换为浮点数或双精度数。例如,它应该隐式转换为这两种类型。它还应该有 std::common_type (http://en.cppreference.com/w/cpp/types/common_type) 对其行为类似,因为它 std::common_types 对其他浮点类型的行为类似。这意味着std::common_type<my_float16, float>::type = floatstd::common_type<my_float16, double>::type = doublestd::common_type<my_float16, T>::type = my_float16 其中T 是任何整数类型。

我需要编写哪些构造函数和强制转换运算符才能完成这项工作?任何帮助将不胜感激!

我的other recent question 可能是相关的。

编辑:好的,我已经像 Anton 那样构建了一个最小的示例。这是

struct float16 {
    explicit operator int() {
        return 0;
    }

    operator float() {
        return 0.0f;
    }
};

这对 float 和 float16 有正确的公共类型,但 int 和 float16 的公共类型仍然是 int。我不明白。

【问题讨论】:

标签: c++ c++11 std


【解决方案1】:

我认为您不能完全理解这一点,因为 C++ 核心语言对待本地定义的转换(例如,charint)与用户定义的转换(即使它们是隐式的)不同。

例如之后

struct float16 { float16(int) {} }; // cast int->float16 is implicit

struct Foo { Foo(const double&){} };  // constructor accepts a double&
struct Bar { Bar(const float16&){} }; // constructor accepts a float16&

void foo(const Foo&) {}
void bar(const Bar&) {}

调用foo(3) 是有效的,因为整数3 可以隐式转换为double 并且foo 接受Foo 实例,该实例可以由用户定义的double 隐式构造转换(不是explicitFoo 构造函数)。

但是bar(3)无效有效,因为这样的调用需要两个隐式的用户定义转换(intfloat16float16Bar),这不是允许。

【讨论】:

  • 感谢@6502。我担心你可能是对的,但我不确定。
  • 您能否指出标准中的某个地方表明情况如此?如果不可能,我想清楚地了解这是在哪里规定的。
  • @user2333829:查看编辑,我添加了一个示例。请注意,C++ 重载解析的确切规则(至少对我而言)太复杂了,无法准确地学习它们,而且我不排除存在更复杂的情况。
【解决方案2】:

如果您将其实现为结构/类类型,请提供所有相关运算符和构造函数的重载。如果类同时支持与其他类型之间的转换,请查看该类所需的指南。

如果您希望您的班级与std::common_typestd::numeric_limits 等标准模板很好地配合使用,您将需要为这些模板提供适当的专业化。最好阅读实际标准来描述此类专业化的要求,但周围可能有一些教程材料(我见过很好的专业介绍材料std::numeric_limits,但不是std::common_type)。

除非您使用特定于编译器的类型,否则您的类型与内置标准类型(intfloat 等)的匹配方式始终存在一些限制。

【讨论】:

  • 谢谢,彼得。我的问题实际上是需要实现哪些构造函数和运算符才能使其工作。我有一个实现了其中许多的类,但我仍然没有得到我想要的确切行为(这是我上面指定的)。至于重载std::common_type,这是我最后的手段——我宁愿让事情正常工作,以便std::common_type使用三元运算符的返回类型自然地工作。
  • 在我的脑海中,最小值是所有数字运算符(operator+() 等)、所有op= 运算符(operator+=() 等)、转换构造函数和相应的operator=() [所有重载对于所有基本类型],所有转换构造函数(operator float() 等)。对于 C++11,建议使用移动构造函数,具体取决于类的内部结构。不要提供按位运算符。供应流插入和提取操作员。可以链接的运算符(如=+=)返回引用,其他按值返回。
  • 嘿彼得。为了让 std::common_type 工作,我认为只需要实现构造函数(甚至不确定移动构造函数)和强制转换运算符。剩下的就是这些特定的操作,当然,它们很有用,但不会影响我相信的 std::common_type 之类的东西。
  • 是的,但是除了让它与std::common_type 一起工作之外,还有更多“行为与浮点、双精度和所有整数类型的适当行为”。 std::common_type 捕获了需求的一个子集。
  • 这是真的!但是 std::common_type 让我感到困惑。
【解决方案3】:

我将针对这个问题提供我自己的答案。

我现在同意 6502,我认为这不是一件容易的事。我发现这样做的唯一方法是为每种可能的类型组合提供运算符重载。这可以使用模板以稍微更好的方式完成(Boost 运算符,http://www.boost.org/doc/libs/1_59_0/libs/utility/operators.htm 就是一个很好的例子),但这仍然是大量的工作和样板代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-15
    • 1970-01-01
    • 2016-09-14
    • 2013-03-20
    相关资源
    最近更新 更多