首页 > 解决方案 > 如何将可变参数放入具有继承的元素向量?

问题描述

我使用 c++ 17 并拥有下一组类

class A {
public:
    virtual void fun() = 0;
};

class B : public A {
public:
    void fun() override {
    }
};

class C : public A {
public:
    void fun() override {
    }
};

我想要一个函数过程,它接受变量的变量列表并返回A的向量(一个基类)

std::unique_ptr<B> b1(new B());
std::unique_ptr<B> b2(new B());
std::unique_ptr<C> c1(new C());
std::unique_ptr<C> c2(new C());

auto vec = process<A>(b1, b2, c1, c2);

对于使用initializer_list我必须知道传递参数的确切类型。

我看不到使用 viriardic 模板的方法,因为我不知道如何正确解压缩参数。

template <typename T, typename... Rest>
std::vector<std::unique_ptr<T>> process(std::unique_ptr<T> t, std::unique_ptr<Rest>... rest) {
  std::vector<std::unique_ptr<T>> A = process<std::unique_ptr<T>>(rest...);
  std::vector<std::unique_ptr<T>> B = process(t);
  std::vector<std::unique_ptr<T>> AB;
  AB.reserve(A.size() + B.size());
  AB.insert(AB.end(), A.begin(), A.end());
  AB.insert(AB.end(), B.begin(), B.end());
  return AB;
}

template <typename T>
std::vector<std::unique_ptr<std::unique_ptr<T>>> process(std::unique_ptr<T> t) {
  return std::vector<std::unique_ptr<T>>{t};
}

template <typename T, typename... Rest>
std::vector<std::unique_ptr<T>> process(std::unique_ptr<Rest>... rest) {
  std::vector<std::unique_ptr<T>> vector;
  auto va = {rest...};
  for (auto el : va) {
    process(el);
  }
  return vector;
}

有没有简单的方法来实现一个接受可变参数并返回一个向量的函数?

标签: c++c++17

解决方案


这是折叠表达式的一个很好的用例。

#include <memory>
#include <iostream>
#include <vector>

class A {
public:
    virtual void fun() = 0;
};

class B : public A {
public:
    void fun() override {
    }
};

class C : public A {
public:
    void fun() override {
    }
};

template <typename T, typename... Args>
auto process(Args&&... args) {
    std::vector<std::unique_ptr<T>> vec;
    vec.reserve(sizeof...(Args));
    (vec.emplace_back(std::move(args)), ...);
    return vec;
}

int main() {
    std::unique_ptr<B> b1(new B());
    std::unique_ptr<B> b2(new B());
    std::unique_ptr<C> c1(new C());
    std::unique_ptr<C> c2(new C());

    auto vec = process<A>(b1, b2, c1, c2);
}

请注意,这里我们窃取了 b1、b2、c1 和 c2 拥有的对象,并且它们已被移动到向量中。对于使用您的代码的人来说,这可能有点令人惊讶。

通常,当您想要移动或拥有某些东西时,您想在呼叫站点明确说明以避免混淆。

我们可以通过按值获取我们的论点来强制执行这一点。那么只有在调用站点使用时才可以使用std::unique_ptrs调用。std::move

像这样的东西。

template <typename T, typename... Args>
auto process(Args... args) {
    std::vector<std::unique_ptr<T>> vec;
    vec.reserve(sizeof...(Args));
    (vec.emplace_back(std::move(args)), ...);
    return vec;
}

int main() {
    std::unique_ptr<B> b1(new B());
    std::unique_ptr<B> b2(new B());
    std::unique_ptr<C> c1(new C());
    std::unique_ptr<C> c2(new C());

    auto vec = process<A>(std::move(b1), std::move(b2), std::move(c1), std::move(c2));
}

现在不移动原来的就不能调用函数了std::unique_ptr,所以在调用处会很清楚b1、b2、c1、c2的内容已经被取走了。


推荐阅读