解压缩可变参数模板以initializer_list并同时调用两个函数

Unpack variadic template to initializer_list and call two functions at once

提问人:Ragdoll Car 提问时间:7/10/2023 最后编辑:Ragdoll Car 更新时间:7/13/2023 访问量:88

问:

我有两个向量:

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);
}

但由于 .当前实现使用两个迭代器创建。在这种情况下,我想要的是有一个 4 个迭代器指向这两个向量的第一个和一个指向结束元素的迭代器。我希望它是 , , , .operator,initializer_listinitializer_listbeginendbeginend

C++ C++17 variadic-templates 初始值设定项列表 参数解包

评论

0赞 Ted Lyngmo 7/10/2023
您是否需要它们交错,或者会起作用?begin, end, begin, endbegin, begin, end, end
0赞 Ragdoll Car 7/10/2023
开始,结束,开始,结束。
1赞 Jarod42 7/11/2023
顺便说一句,你的签名很奇怪,Ts 是任何类型,而你只期望,采取可能更合适。std::vector<int>std::initializer_list<std::reference_wrapper<std::vector<int>>>
0赞 Ragdoll Car 7/11/2023
问题比你想象的要复杂。为了问题的简单性,我修改了我的源代码。我收到的答案解决了我的问题。

答:

4赞 Ted Lyngmo 7/10/2023 #1

我认为你最好的办法是以 s 的形式添加迭代器: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)}...
    };
}

现在,这将有两个带有 和 迭代器的 s,即总共 4 个迭代器。initializer_liststd::pairbegin()end()

评论

0赞 Ragdoll Car 7/10/2023
这是一个很好的答案,但不幸的是,我不能在我的.是否有可能在内部没有嵌套类型的情况下做到这一点?std::pairstd::initializer_liststd::initializer_list
1赞 Ted Lyngmo 7/10/2023
@RagdollCar嗯,我需要考虑一下:-)
6赞 Jarod42 7/10/2023 #2

您可以创建数组而不是: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;
}

演示

4赞 Artyer 7/10/2023 #3

您可以制作一个长度增加一倍的新包:

#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))), ...);
    }

    // ...
}

评论

0赞 Ragdoll Car 7/10/2023
就是这样!谢谢!