28

Wrapperオーバーロードされた乗算operator*=とを持つ単純な int クラスを考えてみましょうoperator*。「古いスタイル」の演算子のオーバーロードについてoperator*は、の観点から定義できます。また、 Boost.Operatorsや@DanielFreyによるその最新の化身df.operators などのoperator*=ライブラリもあり、ボイラープレートを削減します。

ただし、新しい 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