【问题标题】:Use vector::insert with varidic arguments使用带有可变参数的 vector::insert
【发布时间】:2015-11-15 10:38:36
【问题描述】:

我想使用带有可变参数的模板函数将许多向量组合为一个。 在我当前的代码下方,我遇到了三个或更多向量的问题:

#include <iostream>
#include <vector>
#include <numeric>

template<typename _Ty, typename ..._Args>
std::vector<_Ty> combine(const std::vector<_Ty> &a, const _Args &...args) {
  // Determine size of new vector
  std::vector<std::size_t> sizes = { a.size(), args.size()... };
  std::size_t size = std::accumulate(sizes.begin(), sizes.end(), 0);
  // Create vector with new size
  std::vector<_Ty> result(size);
  // Insert all vectors into this one
  result.insert(a.begin(), a.end(), result.end());
  result.insert(result.end(), args.begin()..., args.end()...);
  return result;
}

int main(int argc, char *argv[], char *envp[]) {
  std::vector<int> a = { 0, 1, 2, 3, 4 };
  std::vector<int> b = { 4, 3, 2, 1, 0 };
  std::vector<int> c = { 1, 1, 1, 1 };

  std::cout << combine(a, b).size() << std::endl;
  std::cout << combine(a, b, c).size() << std::endl; // <-- Does not compile

  std::cin.ignore();

  return 0;
}  

所以确切的问题是 combine(a, b, c) 无法编译。我知道为什么。因为这一行:

result.insert(result.end(), args.begin()..., args.end()...);

编译成:

result.insert(result.end(), b.begin(), c.begin(), b.end(), c.end());

但我不知道如何使用可变参数调用 result.insert,因此它会编译为:

result.insert(result.end(), b.begin(), b.end());
result.insert(result.end(), c.begin(), c.end());

一种可能性是:

std::vector<std::vector<_Ty> all = { a, args...};
for (const auto &vec : all) {
    result.insert(vec.begin(), vec.end());
}

但这需要所有向量的第二个副本....有什么想法吗?谢谢!

【问题讨论】:

    标签: c++ templates c++11 vector arguments


    【解决方案1】:

    标准技巧是只使用扩展器之类的东西:

    template<typename _Ty, typename ..._Args>
    std::vector<_Ty> combine(std::vector<_Ty> a, const _Args &...args)
                          // ^^^^^^^^^^^^^^^^^^ by-value
    {
        using expander = int[];
        expander{0,
            (void(a.insert(a.end(), args.begin(), args.end())), 0)...
        };
        return a;
    }
    

    旁注,_Ty_Args 是保留名称。

    【讨论】:

    • @PaoloM 查看 T.C. 的回答 here。那里可能有更好的解释,但这是我发现的第一个我喜欢的解释。
    • @Barry 是否定义了评估初始化程序的顺序?
    • 澄清一下:它是为列表初始化定义的(C++11 §8.5.4[dcl.init.list]/4),但这是聚合初始化。
    • @ex-bart 聚合初始化是一种列表初始化。
    • @ex-bart “T 类型的对象或引用的列表初始化定义如下:[...] — 否则,如果 T 是聚合,则执行聚合初始化。”该子句与列表初始化分开。这是其中的一个特例。
    猜你喜欢
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多