Guidelines to do constexpr operator-overloading?

c++, c++11, c++14, constexpr, operator-overloading

Solution

I could not find an idiomatic solution for C++11 (although as a workaround, DyP's suggestion seems acceptable to me).

In C++14 however, where `constexpr` does not imply `const` (see Annex C.3.1 of the C++14 Standard Draft n3690), you could simply define both `operator *=` and `operator *` as `constexpr`, and define the latter in terms of the former, as usual:

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

Here is a live example, where the above program is being compiled with `-std=c++1y` on Clang - unfortunately, GCC does not seem to implement this rule yet.

Problem

Consider a simple int `Wrapper` class with overloaded multiplication `operator*=` and `operator*`. For "old-style" operator-overloading, one can define `operator*` in terms of `operator*=`, and there are even libraries like Boost.Operators and its modern incarnation df.operators by @DanielFrey that reduce the boilerplate for you. However, for compile-time computations using the new C++11 `constexpr`, this convenience disappears. A `constexpr operator*` cannot call `operator*=` because the latter modifies its (implicit) left argument. Furthermore, there is no overloading on constexpr, so adding an extra `constexpr operator*` to the existing `operator*` results in an overload resolution ambiguity. My current approach is: ``` #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. My problems with this are: - duplication of the multiplication logic in both `operator*=` and `operator*`, instead of `operator*` being expressed in terms of `operator*=` - hence, Boost.Operators no longer works to reduce the boilerplate for writing many other arithmetic operators Question: is this the recommended C++11 way of having both a run-time `operator*=` and mixed run-time/compile-time `constexpr operator*`? Does C++14 change anything here to e.g. reduce the logic duplication? UPDATE: The answer by @AndyProwl is accepted as idiomatic but as per suggestion of @DyP, in C++11 one could reduce the logic duplication at the expense of an extra assignment and counter-intuitive style ``` // define operator*= in terms of operator* Wrap& operator*=(Wrap const& rhs) { *this = *this * rhs; return *this; } ```

Original source

Related problems