做constexpr运算符重载的指南?

Tem*_*Rex 26 c++ operator-overloading constexpr c++11 c++14

考虑一个简单的INT Wrapper与重载乘法类operator*=operator*.对于"旧式"运算符重载,可以定义operator*,operator*=甚至还有像Boost.Operators这样的库以及@DanielFrey的现代化版本操作,它们可以为您减少样板.

但是,对于使用新C++ 11的编译时计算constexpr,这种便利性消失了.A constexpr operator*无法调用,operator*=因为后者修改了它的(隐式)左参数.此外,constexpr没有过载,因此constexpr operator*在现有operator*结果中添加额外的过载分辨率模糊.

我目前的做法是:

#include <iostream>

struct Wrap
{
    int value;    

    Wrap& operator*=(Wrap const& rhs) 
    { value *= rhs.value; return *this; }

    // need to comment this function because of overloading ambiguity with the constexpr version
    // friend Wrap operator*(Wrap const& lhs, Wrap const& rhs)
    // { return Wrap { lhs } *= rhs; }    

    friend constexpr Wrap operator*(Wrap const& lhs, Wrap const& rhs)
    { return { lhs.value * rhs.value }; }
};

constexpr Wrap factorial(int n)
{
    return n? factorial(n - 1) * Wrap { n } : Wrap { 1 };    
}

// want to be able to statically initialize these arrays
struct Hold
{
    static constexpr Wrap Int[] = { factorial(0), factorial(1), factorial(2), factorial(3) };
};

int main() 
{
    std::cout << Hold::Int[3].value << "\n"; // 6
    auto w = Wrap { 2 };
    w *= Wrap { 3 };
    std::cout << w.value << "\n"; // 6
}
Run Code Online (Sandbox Code Playgroud)

现场输出.我的问题是:

  • 在两个乘法逻辑的复制operator*=operator*,而不是operator*在形式表示operator*=
  • 因此,Boost.Operators不再用于减少用于编写许多其他算术运算符的样板

问题:这是推荐的C++ 11兼具运行时operator*=和混合运行时/编译时的方法constexpr operator*吗?C++ 14是否会改变任何内容以减少逻辑重复?

更新:@AndyProwl的答案被认为是惯用的,但根据@DyP的建议,在C++ 11中,可以减少逻辑重复,但会牺牲额外的赋值和反直觉的风格

    // define operator*= in terms of operator*
    Wrap& operator*=(Wrap const& rhs) 
    { *this = *this * rhs; return *this; }
Run Code Online (Sandbox Code Playgroud)

And*_*owl 20

我无法找到C++ 11的惯用解决方案(虽然作为一种解决方法,DyP的建议似乎对我来说是可接受的).

然而,在C++ 14中,constexpr并不暗示const(参见C++ 14标准草案n3690的附录C.3.1),您可以像往常一样简单地定义两者operator *=operator *as constexpr,并根据前者定义后者:

struct Wrap
{
    int value;    

    constexpr Wrap& operator *= (Wrap const& rhs) 
    { value *= rhs.value; return *this; }

    friend constexpr Wrap operator * (Wrap const& lhs, Wrap const& rhs)
    { return Wrap(lhs) *= rhs; }    
};
Run Code Online (Sandbox Code Playgroud)

这是一个实例,上面的程序是用-std=c++1yClang 编译的- 不幸的是,GCC似乎还没有实现这个规则.

  • @TemplateRex:是的,我自己也考虑过这个问题,但是我没有把它作为解决方案发布,因为它会违反标准做法.当为C++ 14准备好启用更改时恢复指南将是不合适的IMO.但是,作为C++ 11的解决方法,它应该是可以接受的.老实说,我认为性能不会成为问题 - 我不是编译专家,但我希望优化器能够为这些简单的函数执行大量的内联.此外,我试图避免过早优化,并避免因为对性能的假设而拒绝设计. (5认同)
  • @TemplateRex:是的,一些`constexpr`限制被解除了,包括函数必须是一个`return`语句.不确定工作文件,但如果你比较C++ 11和C++ 14标准草案n3690的第7.1.5/3段,你可以看到差异是什么 (2认同)