28

考虑一个简单的 intWrapper类,它具有重载的乘法operator*=operator*. 对于“旧式”运算符重载,可以根据 定义operator*operator*=甚至还有像Boost.Operators这样的库以及@DanielFrey的现代化身df.operators可以为您减少样板文件。

然而,对于使用新的 C++11 的编译时计算constexpr,这种便利就消失了。Aconstexpr 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
}

现场输出在这里。我的问题是:

  • 和 中的乘法逻辑的重复operator*=operator*而不是operator*表示为operator*=
  • 因此,Boost.Operators 不再用于减少编写许多其他算术运算符的样板文件

问题:这是推荐的具有运行时operator*=和混合运行时/编译时的 C++11 方式constexpr operator*吗?C++14 是否改变了这里的任何东西以减少逻辑重复?

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

    // define operator*= in terms of operator*
    Wrap& operator*=(Wrap const& rhs) 
    { *this = *this * rhs; return *this; }
4

1 回答 1

20

我找不到 C++11 的惯用解决方案(尽管作为一种解决方法,我似乎可以接受DyP 的建议)。

然而,在 C++14 中, whereconstexpr并不暗示const(参见 C++14 标准草案 n3690 的附件 C.3.1),您可以简单地将operator *=和定义operator *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; }    
};

这是一个现场示例,上面的程序是-std=c++1y在 Clang 上编译的——不幸的是,GCC 似乎还没有实现这个规则。

于 2013-07-19T12:28:27.733 回答