2

少し前に、可変個引数テンプレートのおかげで、Python の chain 関数に相当する C++ を実装しました。この関数は、多くのコンテナーを連続して反復処理するために使用されます。ChainedObjectこれは、名前が何であれ、という名前のジェネレーターを使用した関数の古い作業バージョンです。

template<typename... Iterables>
auto chain(Iterables&&... iters)
    -> ChainObject<Iterables...>
{
    return /* ... */;
}

そして対応するメイン:

int main()
{
    std::vector<int> vec = { 1, 2, 3, 4, 5 };
    std::list<int>   li  = { 6, 7, 8, 9, 10, 11, 12, 13 };
    for (auto& i: chain(vec, li))
    {
        // You can edit a range of iterables
        // as if there was only one of them.
        i *= 5;

        std::cout << i << std::endl;
    }
    return 0;
}

そのメインはうまくいきました。問題の ChainObject に何があるかは気にしないので、見てみましょう。テンプレート テンプレートを使用して、使用されるさまざまなコレクションが同じであることを確認しvalue_type、関数chainを次のように変更しようとしました。

template<typename T, template<typename...> class... Iterables>
auto chain(Iterables<T>&&... iters)
    -> ChainObject<T, Iterables...>
{
    return /* ... */;
}

listこれにより、以前のメイン共有のandが同じ型を共有するようにするためのトリックが行われると考えましたvectorが、代わりに、GCC 4.7.1 から次のエラーが発生します。

関数 'int main()' 内:

エラー: 'chain(std::vector&, std::list&)' の呼び出しに一致する関数がありません

注: 候補は次のとおりです。

注: ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}]

注: ' ' から ' ' への引数 2 の既知の変換はありませstd::list<int>std::list<int>&&

ノート:ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}]

注: ' ' から ' ' への引数 2 の既知の変換はありませstd::list<int>std::list<int>&&

エラー: '' から 'auto&' を推測できません

問題は、右辺値参照を取る関数への引数の受け渡しにあるようです。しかし、最初のバージョンがうまく機能した理由がよくわかりません。テンプレート テンプレートを使用していることに注意してください。

4

1 に答える 1

5

あなたの問題は、T&&テンプレートマジックが型パラメーターに対してのみ機能することです(必要に応じて、左辺値引数の場合などに推測することによって機能します) Tint&実際のタイプがX<T>&&-Xこの場合、「クラステンプレートへの参照」のようなものではなく、クラステンプレートでなければなりません。したがって、最終的には、左辺値 (変数) から暗黙的に取得できない右辺値参照を渡す必要があります。

そうは言っても、以前のコードに戻って、value_types が SFINAE と同じ (または互換性があるなど) であることを確認することをお勧めします。

大まかなコード スケッチ (厳密な等価の場合):

template <class ... Ts> struct all_types_equal
{
  static const bool value = false;
};

template <class T>
struct all_types_equal<T>
{
  static const bool value = true;
};
template <class T, class ... Rest>
struct all_types_equal<T, T, Rest...>
{
  static const bool value = all_types_equal<T, Rest...>::value;
};

template<typename... Iterables>
auto chain(Iterables&&... iters)
    -> typename std::enable_if<all_types_equal<Iterable::value_type...>::value, ChainObject<Iterables...> >::type
于 2012-11-24T01:13:24.233 に答える