从 C++17 中的迭代器范围复制分配到元组
Copy-assigning to a tuple from an iterator range in C++17
我一直希望使用新的 C++17 功能,如折叠表达式和 std::apply()
来简化我使用 std::index_sequence
和 [=14 等工具的一些 C++11 代码=] 对元组进行一些操作。一项任务特别给我带来了一些麻烦:将一系列值(例如从 boost::tokenizer
对象)复制到元组。我有一个可行的解决方案,它在要分配值的元组上调用 std::apply()
,但仍然必须在内部使用 std::initializer_list
(为简单起见,我用一个简单的方法替换了 boost tokenizer 迭代器矢量:
#include <iostream>
#include <vector>
#include <tuple>
template<typename Tuple, typename Iterator>
size_t copy_range_to_tuple(Tuple& tup, Iterator begin, Iterator end) {
size_t count = 0;
auto copy = [&begin,&end,&count] (auto& value) -> bool {
if (begin != end) {
value = *(begin++);
++count;
return true;
} else {
return false;
}
};
std::apply([©](auto&... values) {
std::initializer_list<bool>{copy(values)...};
}, tup);
return count;
}
int main(int,char**) {
std::tuple<int,int,int,int> tup;
std::vector<int> x{4,3,2};
std::cout << "copy count = " << copy_range_to_tuple(tup, x.begin(), x.end()) << std::endl;
std::cout << std::get<0>(tup) << std::endl;
std::cout << std::get<1>(tup) << std::endl;
std::cout << std::get<2>(tup) << std::endl;
std::cout << std::get<3>(tup) << std::endl;
}
输出:
copy count = 3
4
3
2
0
与我的 C++11/14 代码相比,这已经是一个巨大的胜利,后者(由于缺少 std::apply()
)使用索引序列将迭代器与不同的元组元素相匹配。然而,我仍然有一种感觉,或者希望,这可以通过折叠表达式进一步简化,从而消除对初始化列表的需要。准确的说,我是希望我能做一个展开 copy(values)
的折叠表达式。这可能吗,或者现代 C++ 是否还有其他一些技巧可以使它不那么冗长? (摆脱 copy
lambda 也很好,但我认为为了检查有效的迭代器,类似的东西是不可避免的)。
带有折叠表达式的版本可能如下所示:
std::tuple<int,int,int,int> t;
std::vector<int> v{4,3};
auto beg = v.begin();
auto end = v.end();
std::apply([&](auto&... values){
auto getValue = [&](){ return (beg != end) ? *beg++ : 0; }; // returns 0 if range is too small
((values = getValue()),...);
}, t);
std::cout << std::get<0>(t) << std::endl; // 4
std::cout << std::get<1>(t) << std::endl; // 3
std::cout << std::get<2>(t) << std::endl; // 0
std::cout << std::get<3>(t) << std::endl; // 0
我想您可以简单地使用迭代器并调用 std::apply()
;我是说
auto it = v.begin();
std::apply([&](auto & ... values)
{ ((it != v.end() ? values = *it++ : values), ... ); }, t);
下面是一个完整的编译示例
#include <tuple>
#include <vector>
#include <iostream>
int main ()
{
std::tuple<int,int,int,int> t;
std::vector<int> v{4,3,2};
auto it = v.begin();
std::apply([&](auto & ... values)
{ ((it != v.end() ? values = *it++ : values), ... ); }, t);
std::cout << std::get<0>(t) << std::endl; // 4
std::cout << std::get<1>(t) << std::endl; // 3
std::cout << std::get<2>(t) << std::endl; // 2
std::cout << std::get<3>(t) << std::endl; // 0
}
我一直希望使用新的 C++17 功能,如折叠表达式和 std::apply()
来简化我使用 std::index_sequence
和 [=14 等工具的一些 C++11 代码=] 对元组进行一些操作。一项任务特别给我带来了一些麻烦:将一系列值(例如从 boost::tokenizer
对象)复制到元组。我有一个可行的解决方案,它在要分配值的元组上调用 std::apply()
,但仍然必须在内部使用 std::initializer_list
(为简单起见,我用一个简单的方法替换了 boost tokenizer 迭代器矢量:
#include <iostream>
#include <vector>
#include <tuple>
template<typename Tuple, typename Iterator>
size_t copy_range_to_tuple(Tuple& tup, Iterator begin, Iterator end) {
size_t count = 0;
auto copy = [&begin,&end,&count] (auto& value) -> bool {
if (begin != end) {
value = *(begin++);
++count;
return true;
} else {
return false;
}
};
std::apply([©](auto&... values) {
std::initializer_list<bool>{copy(values)...};
}, tup);
return count;
}
int main(int,char**) {
std::tuple<int,int,int,int> tup;
std::vector<int> x{4,3,2};
std::cout << "copy count = " << copy_range_to_tuple(tup, x.begin(), x.end()) << std::endl;
std::cout << std::get<0>(tup) << std::endl;
std::cout << std::get<1>(tup) << std::endl;
std::cout << std::get<2>(tup) << std::endl;
std::cout << std::get<3>(tup) << std::endl;
}
输出:
copy count = 3
4
3
2
0
与我的 C++11/14 代码相比,这已经是一个巨大的胜利,后者(由于缺少 std::apply()
)使用索引序列将迭代器与不同的元组元素相匹配。然而,我仍然有一种感觉,或者希望,这可以通过折叠表达式进一步简化,从而消除对初始化列表的需要。准确的说,我是希望我能做一个展开 copy(values)
的折叠表达式。这可能吗,或者现代 C++ 是否还有其他一些技巧可以使它不那么冗长? (摆脱 copy
lambda 也很好,但我认为为了检查有效的迭代器,类似的东西是不可避免的)。
带有折叠表达式的版本可能如下所示:
std::tuple<int,int,int,int> t;
std::vector<int> v{4,3};
auto beg = v.begin();
auto end = v.end();
std::apply([&](auto&... values){
auto getValue = [&](){ return (beg != end) ? *beg++ : 0; }; // returns 0 if range is too small
((values = getValue()),...);
}, t);
std::cout << std::get<0>(t) << std::endl; // 4
std::cout << std::get<1>(t) << std::endl; // 3
std::cout << std::get<2>(t) << std::endl; // 0
std::cout << std::get<3>(t) << std::endl; // 0
我想您可以简单地使用迭代器并调用 std::apply()
;我是说
auto it = v.begin();
std::apply([&](auto & ... values)
{ ((it != v.end() ? values = *it++ : values), ... ); }, t);
下面是一个完整的编译示例
#include <tuple>
#include <vector>
#include <iostream>
int main ()
{
std::tuple<int,int,int,int> t;
std::vector<int> v{4,3,2};
auto it = v.begin();
std::apply([&](auto & ... values)
{ ((it != v.end() ? values = *it++ : values), ... ); }, t);
std::cout << std::get<0>(t) << std::endl; // 4
std::cout << std::get<1>(t) << std::endl; // 3
std::cout << std::get<2>(t) << std::endl; // 2
std::cout << std::get<3>(t) << std::endl; // 0
}