解包可变模板为初始化列表并同时调用两个函数。

huangapple go评论64阅读模式
英文:

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。在这种情况下,我希望它包含指向这两个向量的第一个和最后一个元素之前的位置的四个迭代器。我希望它是 beginendbeginend

英文:

I have two vectors:

std::vector&lt;int&gt; v1{ 1, 2, 3 };
std::vector&lt;int&gt; 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&lt;class... Ts&gt;
void foo(Ts... args)

and inside above function I want to unpack all arguments. So far I implemented:

template&lt;class... Ts&gt;
void foo(Ts... args)
{
  std::initializer_list&lt;std::vector&lt;int&gt;::iterator&gt; il{
    (std::begin(args), std::end(args))...
  };
}

int main()
{
  std::vector&lt;int&gt; v1{ 1, 2, 3 };
  std::vector&lt;int&gt; 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&lt;class... Ts&gt;
auto foo(Ts&amp;... args)
{
    std::array&lt;typename std::common_type_t&lt;std::decay_t&lt;Ts&gt;...&gt;::iterator, 2 * sizeof...(Ts)&gt; res;

    std::size_t i = 0;
    ((res[i++] = args.begin(), res[i++] = args.end()), ...);

    return res;
}

Demo

答案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::pairs:

template&lt;class... Ts&gt;
void foo(Ts... args) {
    std::initializer_list&lt;std::pair&lt;std::vector&lt;int&gt;::iterator,
                                    std::vector&lt;int&gt;::iterator&gt;&gt; il
    {
        {std::begin(args), std::end(args)}...
    };
}

This initializer_list would now have two std::pairs 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 &lt;vector&gt;
#include &lt;utility&gt;
#include &lt;tuple&gt;

namespace detail {

template&lt;std::size_t... I, class... Ts&gt;
void foo_impl(std::index_sequence&lt;I...&gt;, Ts&amp;... args) {
    std::initializer_list&lt;std::vector&lt;int&gt;::iterator&gt; il{
        [&amp;]() -&gt; std::vector&lt;int&gt;::iterator {
            auto&amp; vec = std::get&lt;I/2u&gt;(std::tie(args...));
            return I % 2u == 0u ? std::begin(vec) : std::end(vec);
        }()...
    };

    // ...
}

}

template&lt;class... Ts&gt;
void foo(Ts... args) {
    return detail::foo_impl(std::make_index_sequence&lt;sizeof...(args)*2u&gt;{}, args...);
}

Or consider if you need an initializer_list at all. You might be able to use an array:

template&lt;class... Ts&gt;
void foo(Ts... args) {
    std::vector&lt;int&gt;::iterator il[sizeof...(args)*2u];
    {
        auto* p = std::begin(il);
        (((*p++ = std::begin(args)), (*p++ = std::end(args))), ...);
    }

    // ...
}

huangapple
  • 本文由 发表于 2023年7月10日 19:15:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76653171.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定