我有具有以下签名的方法:
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
,您不能--编译时间--提取size()
值。
因此,只有将要从向量中使用的元素数作为编译时的已知值传递给CallDoStuff()
,才能获得所需的内容。
例如,您可以将其作为模板值传递。
使用helper函数,您可以编写如下
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>{}); }
它是可调用的,而无需如下解释CCD_
std::array<int, 5u> arr { 2, 3, 5, 7, 11 };
CallDoStuff(arr); // no more <5u>
结束语:注意std::make_index_sequence
和std::index_sequence
只能从C++14开始使用。在C++11中,您必须以某种方式替换它们。
只要提供参数数量的上限,这是可能的。
利用Xeo在C++11:上实现std::index_sequence
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{});
}
在Wandbox 上实时观看
这是不可能的,模板方法调用在编译时绑定,但std::vector
直到运行时才知道它包含多少项,因此无法混合这两个概念。
DoStuff(vElemets...);
在这里,编译器应该根据vElements
有多少元素来选择正确的实现。您可以看到这种想法的缺陷,因为std::vector
只是一个在调用时可以包含任意数量项的对象。