2016-06-14 6 views
1

ソリューションで多くの範囲に参加SO boost::range::join for multiple ranges質問gnzlbg年代のセクションでは、それがboost::joinboost::make_iterator_rangeを呼び出すカスタム関数可変長引数テンプレートに1つのクライアントコードの呼び出しで多くの範囲に参加することができます意味します。その質問、答え、およびコメントによると、前の2つの範囲を結合することができますし、後者は、前のオーバーロードが使用されていることを確認する必要があります。const 2番目以降のコンテナはstd::forwardで完璧に転送されています。しかし、私のクライアントコードは、最大で3つの引数でしか呼び出すことができません。何もコンパイルに失敗します。何が間違っていて、どのように修正するのですか?そして今、多くの範囲に加わるBoostエンティティがありますか?ブースト::範囲:: 1つのカスタムコール

私はコピー&ペーストOPの実装という、空白のみ読みやすさのためにここでそれを編集して、関連するヘッダを追加しました:

#include <utility> 
#include <boost/range/join.hpp> 

template<class C> 
auto join(C&& c) 
-> decltype(boost::make_iterator_range(std::begin(c), std::end(c))) 
{ 
    return boost::make_iterator_range(std::begin(c), std::end(c)); 
} 

template<class C, class D, class... Args> 
auto join(C&& c, D&& d, Args&&... args) 
-> decltype 
(
    boost::join 
    (
     boost::join 
     (
      boost::make_iterator_range(std::begin(c), std::end(c)), 
      boost::make_iterator_range(std::begin(d), std::end(d)) 
     ), 
     join(std::forward<Args>(args)...) 
    ) 
) 
{ 
    return boost::join 
    (
     boost::join 
     (
      boost::make_iterator_range(std::begin(c), std::end(c)), 
      boost::make_iterator_range(std::begin(d), std::end(d)) 
     ), 
     join(std::forward<Args>(args)...) 
    ); 
} 

と私のクライアントのコードを追加しました:

#include <deque> 
#include <array> 
#include <vector> 
#include <iostream> 

int main() 
{ 
    std::deque<int> deq { 0, 1, 2, 3, 4 }; 
    std::array<int, 4> stl_arr { 5, 6, 7, 8 }; 
    int c_arr[3] { 9, 10, 11 }; 
    std::vector<int> vec { 12, 13 }; 

    for (auto& i : join(deq, stl_arr, c_arr)) 
    { 
     ++i; 
     std::cout << i << ", ";   // OK, prints 1 thru 12 
    } 

    //join(deq, stl_arr, c_arr, vec); // COMPILER ERROR 
} 

答えて

5

二つがあります。物事は進行中です。最初は、意図したとおり、以下の宣言は動作しませんということです。

template<class C> 
auto join(C&& c) 
-> decltype(boost::make_iterator_range(std::begin(c), std::end(c))); 

template<class C, class D, class... Args> 
auto join(C&& c, D&& d, Args&&... args) 
-> decltype 
(
    boost::join 
    (
     boost::join 
     (
      boost::make_iterator_range(std::begin(c), std::end(c)), 
      boost::make_iterator_range(std::begin(d), std::end(d)) 
     ), 
     join(std::forward<Args>(args)...) 
    // ^^^^-- (1) 
    ) 
); 

問題の核心は、スポットで(1)joinの2番目のオーバーロードは、スコープ内にはないということです。 3つの引数を指定すると、Argsパックの長さが1であるため、join(std::forward<Arg0>(arg0))拡張の最初のオーバーロードがであり、範囲はです。

引数が4つ以上ある場合、結果として生じる2回目のオーバーロードは必要ですが、selfsameの遅延戻り型の範囲には含まれません。

それを解決する一つの方法は、クラスのスコープがより寛大であるため、メンバ関数テンプレートのセットに、関数テンプレートのセットを有効にすることです:どのような重要なのクラスのスコープであることを

struct join_type { 
    template<class C> 
    auto operator()(C&& c) const 
    -> decltype(boost::make_iterator_range(std::begin(c), std::end(c))) 
    { 
     return boost::make_iterator_range(std::begin(c), std::end(c)); 
    } 

    template<class C, class D, class... Args> 
    auto operator()(C&& c, D&& d, Args&&... args) const 
    -> decltype 
    (
     boost::join 
     (
      boost::join 
      (
       boost::make_iterator_range(std::begin(c), std::end(c)), 
       boost::make_iterator_range(std::begin(d), std::end(d)) 
      ), 
      (*this)(std::forward<Args>(args)...) 
     ) 
    ) 
    { 
     return boost::join 
     (
      boost::join 
      (
       boost::make_iterator_range(std::begin(c), std::end(c)), 
       boost::make_iterator_range(std::begin(d), std::end(d)) 
      ), 
      (*this)(std::forward<Args>(args)...) 
     ); 
    } 
}; 

constexpr join_type join {}; 

注意、ではない、我々メンバー関数テンプレートの名前としてoperator()を使用することを選択しました。 fooという名前の静的メンバー関数テンプレートを使用することもできますし、転送するクラスの外にある通常の関数テンプレートを使用することもできます。


は、今、私たちは実装がバグだらけであるという点で第二の問題を公開することができ、唯一の引数の奇数で動作します! join(a, b)でも動作しませんが、そのバグは以前はADLによって隠されていた可能性があります(つまり、クライアントは効果的にboost::join(a, b)を呼び出すことになります)(Live On Coliru)。

のは、折り目を書き換えてみましょう:

struct join_type { 
    template<class C> 
    auto operator()(C&& c) const 
    -> decltype(boost::make_iterator_range(begin(c), end(c))) 
    { 
     return boost::make_iterator_range(begin(c), end(c)); 
    } 

    template<typename First, typename Second, typename... Rest> 
    auto operator()(First&& first, Second&& second, Rest&&... rest) const 
    -> decltype((*this)(boost::join(boost::make_iterator_range(begin(first), end(first)), boost::make_iterator_range(begin(second), end(second))), std::forward<Rest>(rest)...)) 
    { 
     return (*this)(boost::join(boost::make_iterator_range(begin(first), end(first)), boost::make_iterator_range(begin(second), end(second))), std::forward<Rest>(rest)...); 
    } 
}; 

constexpr join_type join {}; 

Live On Coliru

関連する問題