【问题标题】:Writing the types of a function applied to parameter pack编写应用于参数包的函数类型
【发布时间】:2015-04-12 04:00:00
【问题描述】:

短版: 我需要向模板类传递参数包,这是将函数应用于另一个参数包的结果。这需要在 using 语句中工作。

背景: 作为一项挑战,我正在编写 python 的zip() 的通用 C++11 版本。为了做到这一点,我编写了一个通用的zipIterator 模板类,它可以用来同时迭代许多迭代器,产生它们值的元组。例如:

#include "zip.hpp"
#include <iostream>
#include <vector>
#include <tuple>

int main(){
    std::vector<int> vec = {0,1,2,3};
    char arr[] = {'a','b', 'c'};
    zipIterator<decltype(vec.begin()), char*, decltype(vec.rbegin())>
        itr(vec.begin(), std::begin(arr), vec.rbegin());
    zipIterator<decltype(vec.begin()), char*, decltype(vec.rbegin())>
        end(vec.end(), std::end(arr), vec.rend());
    for(; itr!=end; ++itr){
        std::cout << "(" << std::get<0>(*itr) << ", " << std::get<1>(*itr)
            << ", " << std::get<2>(*itr) << ")" << std::endl;
    }
}
//output:
//(0, a, 3)
//(1, b, 2)
//(2, c, 1)

问题 我想创建一个zip 容器类,它可以传递容器,并通过在每个容器上调用 std::begin() 和 std::end() 来压缩它们。到目前为止,我有这个:

template<typename... Containers>
class zip{
public:
    using iterator = zipIterator<???>;
    zip(Containers... cs) : begin_(iterator(std::begin(cs)...)),
        end_(iterator(std::end(cs)...)){};
    iterator begin() {return begin_;}
    iterator end() {return end_;}
private:
    iterator begin_;
    iterator end_;
};

我的问题是:用什么代替 ??? 来完成这项工作?到目前为止我已经尝试过 std::begin(std::declval&lt;Containers&gt;())..., decltype(std::begin(Containers)...), std::result_of&lt;std::begin(Containers)&gt;::type..., 以及更多的变化。

对不起,如果这是重复。我阅读了以下 Stack Overflow 答案,它们似乎都是相关的,但我认为它们并不是我想要的:

【问题讨论】:

  • 您的构造函数按值获取Containers,(a) 由于复制,它的效率可能低于您的预期,并且 (b) 在您以后使用时会导致未定义的行为使用存储的迭代器值无效,因为构造函数参数将在完成后被销毁。您可能希望引用 Containers
  • 很好——我的意思是让它通过参考。谢谢!

标签: c++11 variadic-templates decltype


【解决方案1】:
using iterator = zipIterator<decltype(std::begin(std::declval<Containers&>()))...>;

基本思想是... 扩展其左侧的模式。在这里,模式是decltype(std::begin(std::declval&lt;Containers&amp;&gt;())) - 在Containers 类型的左值上调用时std::begin 的返回值的类型。

【讨论】:

  • 谢谢你的解释和解释。这有很大帮助。还有一个问题——“std::declval()”中似乎需要“&”——为什么会这样?
  • @VikingofRock std::begin 不适用于右值容器(它们绑定到 const &amp; 重载),并且完全不适用于右值数组。毕竟,将迭代器检索到即将被销毁的临时对象中没有多大意义。 declval&lt;Containers&gt;() 是一个右值; declval&lt;Containers&amp;&gt;() 是一个左值。
  • 这是有道理的。谢谢!你真的很有帮助。
猜你喜欢
  • 1970-01-01
  • 2022-07-08
  • 1970-01-01
  • 2012-10-16
  • 1970-01-01
  • 2018-08-28
  • 2020-07-04
  • 1970-01-01
  • 2022-01-10
相关资源
最近更新 更多