c++11 - 省略号可以/应该/将适用于元组吗?

标签 c++11 c++14

在 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 中?

最佳答案

用于创建解决方案的基本工具存在于 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++17 中是 proposed)所以你需要自己编写它,例如通过从 C++14 草案中复制它。

直接允许您想要的最接近的提案是 N3728但这还没有被接受,所以不会在 C++14 中。

关于c++11 - 省略号可以/应该/将适用于元组吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20722770/

相关文章:

c++ - 给定另一个迭代器 vector ,如何从 vector 中删除元素

c++ - 编译时已知条件的标准 if/else?

c++ - 使用变体类型列表调用 std::function

c++ - 递归 noexcept 规范

c++ - static_assert 依赖于非类型模板参数(gcc 和 clang 的不同行为)

c++ - 如何初始化用 auto 关键字声明的循环计数器?

c++ - packaged_task 和 async 有什么区别

c++ - 如何将 boost::any_cast 转换为 std::string

c++ - 谁负责 futures 和 promises 的共享状态

c++ - memcpy 可以用于 std::aligned_storage 吗?