展开 std::vector 进入参数包

Expand std::vector into parameter pack

我有具有以下签名的方法:

void DoStuff(int i);
void DoStuff(int i, k);
void DoStuff(int i, int k, int l);

我有一个方法可以调用 DoStuff 方法,如下所示:

void CallDoStuff(const std::vector<int>& vElements) {
  // What magic is supposed to happen here to make vElements an expandable pack?
  DoStuff(vElemets...);
}

有机会实现吗? 使用 std::index_sequence 的方式正确吗?如果是,能否请您提供一个简单的示例,说明如何将其应用到我的问题中?

这是不可能的,模板方法调用是在编译时绑定的,但是 std::vector 直到运行时才知道它包含多少项,因此无法混合这两个概念。

DoStuff(vElemets...);

这里编译器应该根据vElements有多少个元素来选择正确的实现。您会看到这种想法的缺陷,因为 std::vector 只是一个对象,在调用时可以包含任意数量的项目。

问题是,从 std::vector,您不能 -- compile time -- 提取size() 值。

因此,只有当您将作为编译时已知值传递给CallDoStuff()您想要从向量中使用的元素数量时,您才能获得您想要的内容。

您可以将其作为模板值传递。

使用辅助函数,您可以编写如下内容

template <std::size_t ... Is>
void CallDoStuff (std::vector<int> const & vElements,
                  std::index_sequence<Is...> const &)
 { DoStuff(vElements[Is]...); }

template <std::size_t N>
void CallDoStuff (std::vector<int> const & vElements)
 { CallDoStuff(vElements, std::make_index_sequence<N>{}); }

调用可以是

CallDoStuff<5u>(v);

如果你可以使用 std::array 而不是 std::vector,答案就不同了:你可以从类型本身中提取 size(),所以

template <std::size_t N, std::size_t ... Is>
void CallDoStuff (std::array<int, N> const & vElements,
                  std::index_sequence<Is...> const &)
 { DoStuff(vElements[Is]...); }

template <std::size_t N>
void CallDoStuff (std::array<int, N> const & vElements)
 { CallDoStuff(vElements, std::make_index_sequence<N>{}); }

无需解释 N 即可调用,如下所示

std::array<int, 5u>  arr { 2, 3, 5, 7, 11 };

CallDoStuff(arr); // no more <5u>

尾注:注意 std::make_index_sequencestd::index_sequence 仅从 C++14 开始可用。在 C++11 中,您必须以某种方式替换它们。

这是可能的,只要您提供参数数量的上限。

对 C++11 使用 std::index_sequenceXeo's implementation

template <unsigned... Idx>
void trampoline(const std::vector<int>& vElements, seq<Idx...>) {
    return DoStuff(vElements[Idx]...);
}

template <std::size_t Arity>
void trampoline(const std::vector<int>& vElements) {
    return trampoline(vElements, typename gen_seq<Arity>::seq{});
}

template <unsigned... Idx>
void CallDoStuff(const std::vector<int>& vElements, seq<Idx...>) {
    using trampoline_t = void (*)(const std::vector<int>&);
    constexpr trampoline_t trampolines[]{
        trampoline<Idx>...
    };
    trampolines[vElements.size()](vElements);
}

template <std::size_t Max>
void CallDoStuff(const std::vector<int>& vElements) {
    assert(vElements.size() <= Max);
    return CallDoStuff(vElements, typename gen_seq<Max + 1>::seq{});
}

See it live on Wandbox