【问题标题】:Are C++ arithmetic operators capable of aggressive optimization in custom classes?C++ 算术运算符是否能够在自定义类中进行积极优化?
【发布时间】:2020-07-25 05:54:55
【问题描述】:

C++ 允许对标准数据类型(内置整数和浮点类型)使用算术数学表达式进行积极优化。在这些情况下,在遵守 C++ 标准的同时,编译器可以预先计算文字常量、重新排序操作,甚至完全更改操作等(在某些情况下甚至会偏离标准合规性,就像 -Ofast 优化所发生的那样例如,某些编译器中的级别)。

但现在让我们假设您为标量编写自定义类库并为它们实现算术运算符,甚至为常量定义实现您自己的user-defined literals

C++ 规范是否提供了某种机制来在您自己的类的运算符中实现与内置整数和浮点类型相同的优化机会?

想象一下,例如,您有以下内容:

#include <cstdint>

class MyFP16
{
private:
    std::uint16_t m_val;

public:

    MyFP16();
    [...other constructors here...]
    ~MyFP16();

    // Arithmetic operators
    friend MyFP16 operator+(const MyFP16 &c1, const MyFP16 &c2);
    friend MyFP16 operator-(const MyFP16 &c1, const MyFP16 &c2);
    friend MyFP16 operator*(const MyFP16 &c1, const MyFP16 &c2);
    friend MyFP16 operator/(const MyFP16 &c1, const MyFP16 &c2);

    [...rest of arithmetic operators...]

    // Other logic needed
    [...]
};

我能否以所有运算符都具有与float 内置类型完全相同的语义的方式定义此类,以便所有可用于float 的算术表达式优化也可以用于我的类,利用重新排序操作,交换性/关联性,将一些操作转换为其他操作,预先计算常量结果等......?如何?

非常感谢!

【问题讨论】:

  • 你可以尝试看看编译器做了什么。如果没有您的代码,则不清楚其他人应该如何为您做到这一点
  • 也许你期待一些通用的答案,但在编译器优化方面没有通用的答案。唯一知道的方法是编写代码,编译它并查看编译器的输出。如果你不知道,这是一个很棒的工具来做到这一点:godbolt.org
  • 如果你有代码,你可以编译它,看看编译器是否应用了你期望的优化。
  • @cesss 不,你不能告诉编译器你的运算符的数学属性,除非你的编译器支持这样的特定属性。我认为他们通常不会这样做。
  • @2785528 请争论到底 C++ 运算符语义如何属于编译器而不是 C++。这个问题不是关于编译器,而是关于定义与内置类型具有相同语义的运算符,以便这些语义可以用于优化。我将编辑问题以删除“编译器”字样。

标签: c++ operators literals arithmetic-expressions


【解决方案1】:

运算符重载或用户定义的文字没有什么特别之处。

如果您想为编译器提供优化速度的最佳机会,可能会付出更长的编译时间以及在某些情况下更大的二进制文件大小,那么您应该遵循适用于所有函数的常规规则。

将受益于内联的小函数编写为头文件中的内联函数,以便编译器始终可以决定是否内联。

如果内联了一个小函数,那么您将回到对原始类型进行操作的表达式,并且编译器可以使用您已经提到的相同优化方法。

如果编译器不决定内联调用,那么它可能不会根据运算符的数学属性进行优化,因为它不能假设运算符重载(或任何函数)是例如可交换或关联,除非在非常简单的情况下(无论如何都可能被内联)。

还要确保标记每个允许标记constexpr 的函数,以便更容易进行编译时评估并以constexpr 友好的方式编写代码(即仅使用文字类型)。

如果您对编译器所做的优化不够满意,那么一种常见的方法是使用expression templates 方法在编译时收集表达式树并对其进行自己的转换。

【讨论】:

  • 是的,在我编写的示例中,内联是必不可少的优化,但它独立于算术优化。从您在我的问题下方的最后一条评论中,我假设答案是除非您使用内置 C++ 类型,否则无法优化算术表达式。如果是肯定的,那就太可惜了……
  • 我不知道表达式模板。乍一看,它们看起来像一个复杂的主题,但我会更深入地研究它们。无论如何,它们似乎独立于编译器优化级别......无论优化级别如何,转换都将在表达式上完成。非常不幸的是,您不能告诉编译器将具有相同运算符语义的类视为内置类型:-(
  • 我已经改写了原来的问题,以防万一。问题是一样的,但我希望现在能得到更好的解释。
猜你喜欢
  • 2018-08-19
  • 1970-01-01
  • 2022-12-10
  • 1970-01-01
  • 1970-01-01
  • 2014-01-02
  • 1970-01-01
  • 2018-10-10
  • 1970-01-01
相关资源
最近更新 更多