在C ++ 11中,可变参数模板允许使用任意数量的参数调用函数,并且省略号运算符...
允许该可变参数函数对每个参数执行某些操作,即使这些参数不是每个论点都是一样的:
template<typename... Types>
void dummy(Types... ts){} //dummy to allow function calls via parameter expansion
template<typename... Numerics>
void increment5(Numerics&... ns){
dummy(ns+=5 ...); //parameter expansion (need space after 5 because 5. is decimal)
//it means "dummy(ns_first+=5, ns_second+=5, ns_third+=5, etc.)"
}
int main(){
int i = 0;
float f = 1.1;
std::valarray<int> vi = {1,2,3};
increment5(i,f,vi);
cout
<<i<<endl
<<f<<endl
<<vi[0]<<' '<<vi[1]<<' '<<vi[2]<<endl;
}
如果我们定义一个异构值数组(不同数字类型的列表),我们希望能够做同样的事情(能够为每个元素添加一个数字)。但我们必须将元素存储为元组。
//a class of numbers, possibly different
template<typename... Numerics>
class HeterogeneousValueArray{
private:
tuple<Numerics...> inner;
public:
//initialize the internal vector
HeterogeneousValueArray(Numerics... ns): inner(ns...) {}
};
//Given this function, we don't have to explicitly give the types
//when constructing a HVA
template<typename... Numerics>
HeterogeneousValueArray<Numerics...> HeterogeneousValueArray(Numerics... ns){
return HeterogeneousValueArray<Numerics...>(ns);
}
要调用上面的increment5运算符,我们需要进行元组扩展。 As I understand it, this solution would require defining helper functions for each function I want to write.我们也可以递归地定义increment5,但是,每个函数需要两个函数体。
我相信编程语言应该努力设计允许我们编写我们想要编写的代码。所以这就是我想写的。
template<typename... Numerics>
void increment5(HeterogeneousValueArray<Numerics...>& hva){
increment5(hva.inner... ); //expand a tuple
}
或者这个。
template<typename... Numerics>
void increment5(HeterogeneousValueArray<Numerics...>& hva){
dummy((hva.inner+5)... ); //expand a tuple
}
换句话说,我想将一个元组视为参数包。
当然,“编写您想要编写的代码”是理想主义的,实现任何功能都可能存在问题。什么样的问题会使这种功能无法正常工作(歧义?),或者它如何踩到现有代码或功能的脚趾?或者......它是否已经存在于C ++ 14中?
答案 0 :(得分:5)
创建解决方案的基本工具存在于C ++ 14中,但您需要通过额外的辅助函数获得额外的间接级别,类似于您链接到的答案:
template<typename Tuple, std::size_t... I>
void
_increment5(Tuple& t, std::index_sequence<I...>)
{
dummy( std::get<I>(t) += 5 ... );
}
template<typename... Numerics>
void
increment5(HeterogeneousValueArray<Numerics...>& hva)
{
_increment5(hva.inner, std::index_sequence_for<Numerics...>());
}
std::index_sequence_for<T1, T2, T3>
是类型std::index_sequence<0, 1, 2>
的别名,因此当与包扩展一起使用时,它会为参数包的元素创建一系列索引。然后可以通过辅助函数将该序列索引推断为另一个参数包,因此包扩展std::get<I>(t)...
将扩展I
以提取元组的每个元素。
将index_sequence
添加到C ++ 14的提案还添加了一个示例,显示了将函数对象应用于元组的通用apply
函数,这将允许@DyP在上面的注释中建议:
template<typename... Numerics>
void
increment5(HeterogeneousValueArray<Numerics...>& hva)
{
apply(hva.inner, [](auto& n) { n += 5; });
}
apply
函数不在C ++ 14中(但对于C ++已经是proposed 17)所以你需要自己编写它,例如:通过从C ++ 14草案中复制它。
最接近直接允许您想要的内容的提案是N3728,但尚未被接受,因此不会出现在C ++ 14中。