13

現在、タプルの算術演算子のオーバーロードを作成中です。オペレーターは、タプルを繰り返し処理して、個々の要素ごとに操作を実行します。演算子 += の定義は次のとおりです。

template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    return lhs;
}

template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    std::get< I >(lhs) += std::get< I >(rhs);
    return operator +=< Ts..., I + 1 >(lhs, rhs);
}

残念ながら、オペレーターを呼び出そうとすると、GCC 4.6 は使用するオーバーロードを決定できません。例えば:

std::tuple< int, int, int, int > a = std::make_tuple(1, 2, 3, 4), b = std::make_tuple(5, 6, 7, 8);
a += b;

次のエラーが発生します。

:/Workspace/raster/main.cpp:833:7:   instantiated from here
C:/Workspace/raster/main.cpp:809:45: error: no matching function for call to 'operator+=(std::tuple<int, int, int, int>&, const std::tuple<int, int, int, int>&)'
C:/Workspace/raster/main.cpp:809:45: note: candidates are:
C:/Workspace/raster/main.cpp:800:151: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I == sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
C:/Workspace/raster/main.cpp:806:83: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I != sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)

std::enable_if条件が不適切な呼び出しを拒否する必要があるため、これは奇妙です。今のところ、実際に以前の実装であった次の回避策があります。上記のバージョンは、実際には簡略化の試みです。

template< std::size_t I, typename... Ts >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    return lhs;
}

template< std::size_t I, typename... Ts >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    std::get< I >(lhs) += std::get< I >(rhs);
    return assignadd_impl< I + 1, Ts... >(lhs, rhs);
}

template< typename... Ts >
inline std::tuple< Ts... >& operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    return assignadd_impl< 0, Ts... >(lhs, rhs);
}

これはコンパイルされ、期待どおりに動作します。簡易版がコンパイルを拒否するのはなぜですか? ありがとう。

4

1 に答える 1

6

関数またはクラス テンプレートに対して明示的に指定されたテンプレート引数を使用するには、テンプレート パラメーター パックがテンプレート パラメーター リスト全体の最後にある必要があります。Ts...テンプレート パラメーター リストの最後に移動し、呼び出しを適切に変更すると、コードが機能します。現在の C++0x ドラフトのセクション 14.8.2.1では、テンプレート パラメーター リストの末尾にないパラメーター パックは関数呼び出しから推定できない (元のコードが失敗する) と述べていますが、すべてのテンプレートを明示的に指定しています。すべてのケースでへの引数はoperator+=、依然として SFINAE エラーを引き起こします。 前の質問には、それを禁止する正確なテキストへのリンクがあります。IBM のドキュメントによると、これもエラーです。

于 2011-01-29T19:52:04.340 に答える