做constexpr运算符重载的指南?

时间:2013-07-19 11:19:46

标签: c++ c++11 operator-overloading constexpr c++14

考虑一个带有重载乘法Wrapperoperator*=的简单int operator*类。对于“旧式”运算符重载,可以用operator*来定义operator*=,甚至还有Boost.Operators等库和@DanielFrey的现代化身df.operators为你减少样板。

但是,对于使用新C ++ 11 constexpr的编译时计算,这种便利性消失了。 constexpr operator*无法调用operator*=,因为后者会修改其(隐式)左参数。此外,还有no overloading on 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
}

Live output here。我的问题是:

  • 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; }

1 个答案:

答案 0 :(得分:19)

我找不到C ++ 11的惯用解决方案(虽然作为一种解决方法,DyP's suggestion似乎对我来说是可接受的)。

在C ++ 14中,constexpr does not imply 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; }    
};

这是一个live example,其中上面的程序是用Clang上的-std=c++1y编译的 - 不幸的是,GCC似乎还没有实现这个规则。