[英]c++ Template function to flatten a vector of vector
我寫了一個模板函數來展平矢量的兩級嵌套向量。 然而,第二級向量可以是另一個向量,unique_ptr到vector,或shared_ptr到vector。
例如:
std::vector<std::unique_ptr<std::vector<int>>> f1;
std::vector<std::shared_ptr<std::vector<int>>> f2;
std::vector<std::vector<int>> f3;
std::vector<std::unique_ptr<std::vector<std::string>>> f4;
std::vector<std::shared_ptr<std::vector<std::string>>> f5;
std::vector<std::vector<std::string>> f6;
我寫了這個代碼,它在coliru上工作
#include <vector>
#include <string>
#include <algorithm>
#include <memory>
#include <iostream>
#include <sstream>
template<typename T>
const T* to_pointer(const T& e) {
return &e;
}
template<typename T>
const T* to_pointer(const std::unique_ptr<T>& e) {
return e.get();
}
template<typename T>
const T* to_pointer(const std::shared_ptr<T>& e) {
return e.get();
}
template <typename T, typename K,
typename = typename std::enable_if<
std::is_same<K, std::unique_ptr<std::vector<T>>>::value or
std::is_same<K, std::shared_ptr<std::vector<T>>>::value or
std::is_same<K, std::vector<T>>::value
>::type
>
std::vector<T> flatten(std::vector<K>& source) {
std::vector<T> result;
size_t size = 0;
for (const auto& e : source) {
size += to_pointer(e)->size();
}
result.reserve(size);
for (const auto& e : source) {
auto ptr = to_pointer(e);
auto begin = ptr->begin();
auto end = ptr->end();
std::copy(begin, end, std::back_inserter(result));
}
return result;
}
但是,想檢查是否有更好的方法來編寫相同的代碼。 感謝您的時間和精力。
如果您希望簡化代碼,可以使用std::accumulate
進行自定義操作,如下所示:
#include <vector>
#include <numeric>
int main() {
std::vector<std::vector<int>> foo {
{ 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }
};
auto bar = std::accumulate(foo.begin(), foo.end(), decltype(foo)::value_type{},
[](auto& dest, auto& src) {
dest.insert(dest.end(), src.begin(), src.end());
return dest;
});
}
我的例子的缺點是它不會為新元素保留空間,但在必要時重新分配它。
我的第一個例子僅適用於具有成員函數insert
成員類型value_type
類型。 這意味着foo
不能是例如std::vector<std::unique_ptr<std::vector<int>>>
。
通過在兩個功能模板上使用SFINAE可以解決上述問題,如下所示:
template<typename T, typename = typename T::value_type>
T flatten(const std::vector<T>& v) {
return std::accumulate(v.begin(), v.end(), T{}, [](auto& dest, auto& src) {
dest.insert(dest.end(), src.begin(), src.end());
return dest;
});
}
template<typename T, typename = typename T::element_type::value_type>
typename T::element_type flatten(const std::vector<T>& v) {
using E = typename T::element_type;
return std::accumulate(v.begin(), v.end(), E{}, [](auto& dest, auto& src) {
dest.insert(dest.end(), src->begin(), src->end());
return dest;
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.