C++将参数包传递给类

3

我希望有一个类,它可以在构造函数中接收相同类型的无限参数,并将它们存储到一个向量中。它应该像这样:

class A(int a, int b, **N time parameter of type T**)
: data(**vector will get N times type T**)
{
}

protected:
vector<T> data;

我应该如何实现它?解决方案可以使用 c++11/14。 我遇到了一些错误,例如“参数包未展开为‘…’”等。


你想如何传递参数?实际上,使用std::vector,你可以编写类似于A<char> a(1, 2, {'a', 'b', 'c'});的代码。 - songyuanyao
T是一种内在类型,就像double一样,还是需要移动的对象? - Richard Hodges
4个回答

9
这份代码示例可能会有所帮助:
#include <vector>
#include <utility>

template<typename T>
class MyClass {
public:
    template<typename ...Args>
    MyClass(int a, int b, Args&& ...args) :data{ std::forward<Args>(args)... } {}
private:
    std::vector<T> data;
};

int main() {
    MyClass<char> sample(1, 2, 'a', 'b');
    return 0;
}

[编辑]: 添加了std::forward,添加了utility的缺失头文件。

你可能需要将参数...args使用std::forward传递给data;除此之外,我更喜欢你的解决方案而不是我的。 - YSC
谢谢!这正是我所寻找的。 - Ron

4
假设T可以是任何东西,甚至是非常大或不可复制的东西,我们希望:
  1. 通过完美转发保持效率。

  2. 检查类型。

std::initializer_list 满足2但不满足1。
简单的可变参数模板扩展满足1但不满足2。
该解决方案使用可变参数模板扩展和 enable_if 来强制实现类型兼容性。
#include <vector>
#include <utility>
#include <string>


namespace detail
{
    constexpr bool all()
    {
        return true;
    }

    template<class...Rest>
    constexpr bool all(bool b, Rest...rest)
    {
        return b and all(rest...);
    };

}


template<class T>
class A
{
public:
    using value_type = T;  // say

    template<class...Rest,
            std::enable_if_t<detail::all(std::is_convertible<Rest, value_type>::value...)>* = nullptr>
    A(int a, int b, Rest&&...rest)
            : a_(a), b_(b)
    {
        this->fill(std::forward_as_tuple(std::forward<Rest>(rest)...),
                   std::make_index_sequence<sizeof...(Rest)>());
    }

private:
    template<class Tuple, std::size_t...Is>
    void fill(Tuple&& t, std::index_sequence<Is...> seq)
    {
        data_.reserve(seq.size());
        using expand = int[];
        void(expand{ 0,
                     (data_.push_back(std::move(std::get<Is>(t))), 0)...
        });
    }
private:
    int a_, b_;
    std::vector<value_type> data_;
};


int main()
{
    using namespace std::literals;

    auto a = A<double>(1, 2, 4.3, 5.5, 6.6);

    auto b = A<std::string>(1, 2, "the", "cat"s, "sat on the mat");

    // error: no matching constructor...
//    auto err = A<std::string>(1, 2, "the", "cat"s, 0.1);

}

0

给你:

#include <iostream>
#include <vector>

template<class T>
struct V
{
    V(int n, std::initializer_list<T> l)
        : data(l)
    {
        (void) n;
    }

    std::vector<T> data;
};

int main()
{
    V<int> v(0,{1,2,3});
}

这并不是一个完美的例子,因为需要使用奇怪的语法(n, {可选参数1, 可选参数2, ...})来构造对象,但它确实提供了所需的行为。


0
以下示例与fr3nzy90的类似,但随着C++17的到来,它将允许从构造函数参数自动推断出T:
template <class T>
class MyContainer {
    private:
    std::vector<T> data;

    public:
    // Take the first T value explicitly so it can be used to deduce
    // T from the constructor arguments (C++17 feature).
    template <class... Ts>
    MyContainer(int a, int b, T const & tval, Ts const &... tvals) :
      data{tval, tvals...} {
        …
    }

    // Special case, empty list, no implicit type deduction, because
    // there is no T value to deduce it from.
    MyContainer(int a, int b) {
        …
    }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接