Diretrizes para fazer sobrecarga de operador constexpr?

Considere um int simplesWrapper classe com multiplicação sobrecarregadaoperator*= eoperator*. Para sobrecarga de operador de "estilo antigo", pode-se definiroperator* em termos deoperator*=, e existem até bibliotecas comoBoost.Operators e sua encarnação modernadf.operators por @DanielFrey que reduz o boilerplate para você.

No entanto, para computações em tempo de compilação usando o novo C ++ 11constexpressa conveniência desaparece. UMAconstexpr operator* não pode ligaroperator*= porque o último modifica seu argumento esquerdo (implícito). Além disso, existesem sobrecarga em constexpr, então adicionando um extraconstexpr operator* ao existenteoperator* resulta em uma ambiguidade de resolução de sobrecarga.

Minha abordagem atual é:

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

Saída ao vivo aqui. Meus problemas com isso são:

duplicação da lógica de multiplicação em ambosoperator*= eoperator*, ao invés deoperator* sendo expressa em termos deoperator*=daqui, Boost.Operators já não trabalha para reduzir o boilerplate para escrever muitos outros operadores aritméticos

Questão: esta é a maneira recomendada C ++ 11 de ter um tempo de execuçãooperator*= e tempo de compilação / tempo de compilação mistoconstexpr operator*? O C ++ 14 muda alguma coisa aqui para, e. reduzir a duplicação lógica?

ATUALIZAR: A resposta de @AndyProwl é aceita como idiomática, mas como por sugestão de @DyP, em C ++ 11 umpoderia reduza a duplicação lógica à custa de uma atribuição extra e estilo contra-intuitivo

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

questionAnswers(1)

yourAnswerToTheQuestion