2014-11-03 93 views
1

我有以下的非多容器的容器簡單的情況下工作:複製從多容器內容到一個容器

template <typename MultiContainer, typename SingleContainer> 
void check (const MultiContainer& container, SingleContainer& v) { 
    if (std::is_same<MultiContainer, typename SingleContainer::value_type>::value) 
     return; 
    if (is_container<typename MultiContainer::value_type>::value) { 
     std::vector<typename MultiContainer::value_type::value_type> a; // Using vector for this first draft. 
     for (const auto& x : container) 
      std::copy (x.begin(), x.end(), std::back_inserter(a)); 
     if (std::is_same<typename MultiContainer::value_type::value_type, typename SingleContainer::value_type>::value) 
      v = a; 
//  else check<decltype(a), SingleContainer>(a, v); // Won't compile 
    } 
} 

template <typename MultiContainer, typename SingleContainer> 
SingleContainer extractFromMultiContainer (const MultiContainer& container) { 
    SingleContainer v; 
    check<MultiContainer, SingleContainer>(container, v); 
    return v; 
} 

int main() { 
    using Multi = std::list<std::vector<int>>; 
    const Multi multi = { {1,2,3}, {4,5}, {6,7,8,9} }; 
// using Multi = std::deque<std::list<std::vector<int>>>; 
// const Multi multi = { { {1,2,3}, {4,5}, {6,7,8,9} }, { {10,11}, {12,13}, {14,15,16} } }; 
    const auto v = extractFromMultiContainer<Multi, std::vector<int>>(multi); 
    for (int x : v) std::cout << x << ' '; // 1 2 3 4 5 6 7 8 9 
} 

但我不能獲得需要的遞歸線上面的'check'函數用於處理container-in-container-in-container的情況(無論事實上嵌套得多深,都必須工作)。我在第一稿中使用vector作爲SingleContainer(我會盡量在後面概括)。順便說一句,我得到is_container的代碼在計算器Determine if a type is an STL container at compile time以前的線程,所以我們可以只取一部分是理所當然的:

template<typename T> 
struct has_const_iterator { 
private: 
    typedef char yes; 
    typedef struct { char array[2]; } no; 

    template<typename C> static yes test(typename C::const_iterator*); 
    template<typename C> static no test(...); 
public: 
    static const bool value = sizeof(test<T>(0)) == sizeof(yes); 
    typedef T type; 
}; 

template <typename T> 
struct has_begin_end { 
    template<typename C> static char (&f(typename std::enable_if< 
     std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)), 
     typename C::const_iterator(C::*)() const>::value, void>::type*))[1]; 

    template<typename C> static char (&f(...))[2]; 

template<typename C> static char (&g(typename std::enable_if< 
     std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::end)), 
     typename C::const_iterator(C::*)() const>::value, void>::type*))[1]; 

    template<typename C> static char (&g(...))[2]; 

    static bool const beg_value = sizeof(f<T>(0)) == 1; 
    static bool const end_value = sizeof(g<T>(0)) == 1; 
}; 

template<typename T> 
struct is_container : std::integral_constant<bool, has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value> {}; 

回答

1

據我瞭解,你想有一個通用的flatten功能。你可以做到這一點,首先規定了基本拼合

template<typename T, bool cont = is_container<typename T::value_type>::value> 
struct flattener { 
    template<typename In, typename Out> 
    static void flatten(In first, In last, Out res); 
}; 

,然後再與偏特對兩個集裝箱

template<typename T> struct flattener<T, true> { 
    template<typename In, typename Out> 
    static void flatten(In first, In last, Out res) { 
     for (; first != last; ++first) 
      flattener<typename T::value_type>::flatten(std::begin(*first), std::end(*first), res); 
    } 
}; 

和非容器類型

template<typename T> struct flattener<T, false> { 
    template<typename In, typename Out> 
    static void flatten(In first, In last, Out res) { 
     std::copy(first, last, res); 
    } 
}; 

您現在可以使用這就像

std::vector<int> v1 = { 1, 2, 3 }; 
std::vector<int> res1; 
flattener<decltype(v1)>::flatten(v1.begin(), v1.end(), std::back_inserter(res1)); 

std::vector<std::vector<int> > v2 = { {9, 8, 7}, {6, 5, 4}, {1, 2, 3} }; 
std::vector<int> res2; 
flattener<decltype(v2)>::flatten(v2.begin(), v2.end(), std::back_inserter(res2)); 

std::vector<std::vector<std::vector<int> > > v3 = { { {9, 8}, {7, 6} }, 
                { {6, 5}, {4, 3} }, 
                { {1, 2}, {3, 4} } }; 
std::vector<int> res3; 
flattener<decltype(v3)>::flatten(v3.begin(), v3.end(), std::back_inserter(res3)); 
+0

做得好! 「靜態無效flatten」函數的前向聲明不是必需的,但我可以看到你想要提及它。 – prestokeys 2014-11-03 23:03:45

+0

我還在學習,所以謝謝你的提示。 – 2014-11-04 13:31:11

+0

你必須意味着你仍然在學習C++語言本身(在你認識的其他語言中)。因爲你的解決方案背後的邏輯可能是獨立於語言的,所以它是高級的思維,我從來沒有想過。 – prestokeys 2014-11-04 15:51:56