子を値で保持する式テンプレートメカニズムのCRTPの標準的な使用を検討してください。
template <typename T, typename>
struct Expr {};
template <typename T>
struct Cst : Expr<T, Cst<T>>
{
Cst(T value) : value(std::move(value)) {}
private:
T value;
};
template <typename T, typename L, typename R>
struct Add : Expr<T, Add<T, L, R>>
{
Add(L l, R r) : l(std::move(l)), r(std::move(r))
private:
L l; R r;
};
等
ここで、演算子を実装するとき、引数は正しい型にダウンキャストされるため、参照で渡す必要があります。問題は、次の4つの(!)バージョンを実装していることに気付くということですoperator+
。
template <typename T, typename L, typename R>
Add<T, L, R> operator+(Expr<T, L>&& l, Expr<T, R>&& r)
{
return Add<T, L, R>(
std::move(static_cast<L&>(l)),
std::move(static_cast<R&>(r)));
}
template <typename T, typename L, typename R>
Add<T, L, R> operator+(const Expr<T, L>& l, Expr<T, R>&& r)
{
return Add<T, L, R>(
static_cast<const L&>(l),
std::move(static_cast<R&>(r)));
}
template <typename T, typename L, typename R>
Add<T, L, R> operator+(Expr<T, L>&& l, const Expr<T, R>& r)
{
return Add<T, L, R>(
std::move(static_cast<L&>(l)),
static_cast<const R&>(r));
}
template <typename T, typename L, typename R>
Add<T, L, R> operator+(const Expr<T, L>& l, const Expr<T, R>& r)
{
return Add<T, L, R>(
static_cast<const L&>(l),
static_cast<const R&>(r));
}
実際、不必要なコピーを最小限に抑えることが目標である場合、一時的なもの(移動可能)と左辺値(コピーする必要がある)を区別する必要があるため、4つのオーバーロードが発生します。
C ++ 03では、「問題ありません」。const参照を使用し、常にコピーします。C ++ 11では、より良い結果が得られます。それがここでの目標です。
追加ロジックを一度書くことができるトリックはありますか、それともここでマクロを書くのが最善のオプションです(ロジックは他の演算子に対して繰り返されるため)?
また、C++11を使用して式テンプレートを作成する方法に関する他の提案も受け付けています。ターミナルノードに格納される値は膨大な数または行列になる可能性があるため、目標はコピーを最小限に抑えることであると考えてください(私の正確なケースでは、ターミナルノードには数メガバイトの補間データが含まれている可能性があり、これらのオブジェクトのコピーは無効になっています--他のオブジェクト、コピーが可能です)。