英文:
Unpack variadic template to initializer_list and call two functions at once
问题
我有两个向量:
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 4, 5, 6 };
我想创建一个 std::initializer_list
对象,其中包含上述向量的第一个和最后一个元素的迭代器。
我想要一个具有可变模板的函数:
template<class... Ts>
void foo(Ts... args)
在上述函数内部,我想要展开所有的参数。到目前为止,我已经实现了:
template<class... Ts>
void foo(Ts... args)
{
std::initializer_list<std::vector<int>::iterator> il{
(std::begin(args), std::end(args))...
};
}
int main()
{
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 4, 5, 6 };
foo(v1, v2);
}
但是由于 operator,
,它的表现不如预期。当前的实现会创建一个包含两个迭代器的 initializer_list
。在这种情况下,我希望它包含指向这两个向量的第一个和最后一个元素之前的位置的四个迭代器。我希望它是 begin
、end
、begin
、end
。
英文:
I have two vectors:
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 4, 5, 6 };
I want to create an object of std::initializer_list
which holds iterators to the first and last elements of above vectors.
I want to have a function with a variadic template:
template<class... Ts>
void foo(Ts... args)
and inside above function I want to unpack all arguments. So far I implemented:
template<class... Ts>
void foo(Ts... args)
{
std::initializer_list<std::vector<int>::iterator> il{
(std::begin(args), std::end(args))...
};
}
int main()
{
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 4, 5, 6 };
foo(v1, v2);
}
but it doesn't work as expected due to operator,
. Current implementation creates initializer_list
with two iterators. What I want in this case is to have an initializer_list
with 4 iterators pointing to the first and one past the end element of these two vectors. I want it to be begin
, end
, begin
, end
.
答案1
得分: 6
你可以创建一个数组,而不是使用initializer_list
:
template<class... Ts>
auto foo(Ts&... args)
{
std::array<typename std::common_type_t<std::decay_t<Ts>...>::iterator, 2 * sizeof...(Ts)> res;
std::size_t i = 0;
((res[i++] = args.begin(), res[i++] = args.end()), ...);
return res;
}
英文:
You might create array instead of initializer_list
:
template<class... Ts>
auto foo(Ts&... args)
{
std::array<typename std::common_type_t<std::decay_t<Ts>...>::iterator, 2 * sizeof...(Ts)> res;
std::size_t i = 0;
((res[i++] = args.begin(), res[i++] = args.end()), ...);
return res;
}
答案2
得分: 4
我认为最好的方法是以std::pair
的形式添加迭代器:
template<class... Ts>
void foo(Ts... args) {
std::initializer_list<std::pair<std::vector<int>::iterator,
std::vector<int>::iterator>> il
{
{std::begin(args), std::end(args)}...
};
}
现在,这个initializer_list
将包含两个带有begin()
和end()
迭代器的std::pair
,总共有4个迭代器。
英文:
I think your best bet is to add the iterators in forms of std::pair
s:
template<class... Ts>
void foo(Ts... args) {
std::initializer_list<std::pair<std::vector<int>::iterator,
std::vector<int>::iterator>> il
{
{std::begin(args), std::end(args)}...
};
}
This initializer_list
would now have two std::pair
s with begin()
and end()
iterators, that is, 4 iterators in total.
答案3
得分: 4
你可以创建一个新的包,其长度是原来的两倍:
#include <vector>
#include <utility>
#include <tuple>
namespace detail {
template<std::size_t... I, class... Ts>
void foo_impl(std::index_sequence<I...>, Ts&... args) {
std::initializer_list<std::vector<int>::iterator> il{
[&]() -> std::vector<int>::iterator {
auto& vec = std::get<I/2u>(std::tie(args...));
return I % 2u == 0u ? std::begin(vec) : std::end(vec);
}()...
};
// ...
}
}
template<class... Ts>
void foo(Ts... args) {
return detail::foo_impl(std::make_index_sequence<sizeof...(args)*2u>{}, args...);
}
或者考虑是否需要使用 initializer_list
。您可能能够使用一个数组:
template<class... Ts>
void foo(Ts... args) {
std::vector<int>::iterator il[sizeof...(args)*2u];
{
auto* p = std::begin(il);
(((*p++ = std::begin(args)), (*p++ = std::end(args))), ...);
}
// ...
}
英文:
You can make a new pack which is double the length:
#include <vector>
#include <utility>
#include <tuple>
namespace detail {
template<std::size_t... I, class... Ts>
void foo_impl(std::index_sequence<I...>, Ts&... args) {
std::initializer_list<std::vector<int>::iterator> il{
[&]() -> std::vector<int>::iterator {
auto& vec = std::get<I/2u>(std::tie(args...));
return I % 2u == 0u ? std::begin(vec) : std::end(vec);
}()...
};
// ...
}
}
template<class... Ts>
void foo(Ts... args) {
return detail::foo_impl(std::make_index_sequence<sizeof...(args)*2u>{}, args...);
}
Or consider if you need an initializer_list
at all. You might be able to use an array:
template<class... Ts>
void foo(Ts... args) {
std::vector<int>::iterator il[sizeof...(args)*2u];
{
auto* p = std::begin(il);
(((*p++ = std::begin(args)), (*p++ = std::end(args))), ...);
}
// ...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论