wrapper
別の typeの型を書き込もうとして、かなり厄介な問題に遭遇しました: 基本となる型に操作を転送T
するいくつかの二項演算子 ( など) を定義したいのですが、これらの演算子が潜在的なものを受け入れる必要があります。を含む組み合わせ:+
wrapper
wrapper
wrapper() + wrapper()
wrapper() + T()
T() + wrapper()
単純なアプローチでは、潜在的なオーバーロードをすべて直接記述します。
しかし、私は重複したコードを書くのが好きではなく、もう少し挑戦したかったので、非常に一般的なテンプレートを使用して実装し、enable_if
.
私の試みは質問の最後に示されています(申し訳ありませんが、これは私が考えることができる限り最小限です)。問題は、無限再帰エラーが発生することです。
- を評価するため
test() + test()
に、コンパイルはすべての潜在的なオーバーロードを調べます。 - ここで定義された演算子は、実際には潜在的なオーバーロードであるため、戻り値の型を構築しようとします。
- 戻り値の型には
enable_if
、それが有効なオーバーロードになるのを防ぐことになっている句がありますが、コンパイラはそれを無視して、decltype
最初の値を計算しようとします。これには ... が必要です。 - ... のインスタンス化
operator+(test, test)
。
そして、私たちは出発点に戻りました。GCC はエラーを吐き出すのに十分です。Clang は単にセグメンテーション違反です。
これに対する適切でクリーンな解決策は何でしょうか? (同じパターンに従う必要がある他の演算子もあることに注意してください。)
template<class T>
struct wrapper { T t; };
// Checks if the type is instantiated from the wrapper
template<class> struct is_wrapper : false_type {};
template<class T> struct is_wrapper<wrapper<T> > : true_type {};
// Returns the underlying object
template<class T> const T& base(const T& t) { return t; }
template<class T> const T& base(const wrapper<T>& w) { return w.t; }
// Operator
template<class W, class X>
typename enable_if<
is_wrapper<W>::value || is_wrapper<X>::value,
decltype(base(declval<W>()) + base(declval<X>()))
>::type operator+(const W& i, const X& j);
// Test case
struct test {};
int main() {
test() + test();
return 0;
}
これは、必要がない限り使用したくない、かなり不格好なソリューションです。
// Force the evaluation to occur as a 2-step process
template<class W, class X, class = void>
struct plus_ret;
template<class W, class X>
struct plus_ret<W, X, typename enable_if<
is_wrapper<W>::value || is_wrapper<X>::value>::type> {
typedef decltype(base(declval<W>()) + base(declval<X>())) type;
};
// Operator
template<class W, class X>
typename plus_ret<W, X>::type operator+(const W& i, const X& j);