将std :: vector展开到参数包中

时间:2019-10-30 21:31:48

标签: c++11 variadic-templates stdvector index-sequence

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

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是否正确?如果是,请您提供一个简单的示例,将其应用于我的问题吗?

3 个答案:

答案 0 :(得分:0)

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

DoStuff(vElemets...);

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

答案 1 :(得分:0)

问题在于,您无法从std::vector-编译 时间-提取size()值。< / p>

因此,仅当您将向量中要使用的元素数量传递给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中,您必须以某种方式替换它们。

答案 2 :(得分:0)

有可能,只要您提供参数数目的上限即可。

std::index_sequence中的Xeo's implementation用于C ++ 11:

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