【问题标题】:Pass array through class constructor using C++ variadic templates通过C ++ Variadic模板通过类构造函数传递数组
【发布时间】:2018-07-06 05:42:17
【问题描述】:

我想使用新的 C++ 范例对一个小型数学库进行现代化改造(我有一个 C++17 编译器)。具体来说,我需要通过构造函数将一个数组传递给一个类。

这是我使用的“经典”旧方式。有效

class Vector {
public:
    long double* elements;
public:
    Vector(int size, long double *array) {
        elements = new long double[size];
        for(int i = 0; i < size; i++) {
            elements[i] = array[i];
        }
    };

    virtual ~Vector() {
        delete []elements;
    }

};

int main() {
    long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    Vector vector = Vector(10, array);
    for (int i = 0; i < 10; i++) {
        std::cout << vector.elements[i] << std::endl;
    }

    return 0;
}

所以,我尝试用我对可变参数模板和参数包的理解来更改 Vector 类。它不起作用

class Vector {

public:
    long double* elements;
public:
    template<typename... Args>
    Vector(Args... args){
        constexpr int size = sizeof...(Args);
        elements = new long double[size]{args...};
    }
};

int main() {
    long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    Vector vector = Vector(array);
    for (int i = 0; i < 10; i++) {
        std::cout << vector.elements[i] << std::endl;
    }

    return 0;
}

编译器返回的错误是

错误:初始化时无法将“long double*”转换为“long double”

    elements = new long double[size]{args...};

我做错了什么? 此外,我想知道是否可以在 main 方法和 Vector 类中使用 std::array 而不是原始数组。

【问题讨论】:

  • 模板在编译时扩展,它不会用它的初始化列表替换array
  • 请使用std::array 而不是这些糟糕的 c 样式数组!
  • std 与一个名为Vector 的类和一个名为vector 的变量一起使用可能是一个非常糟糕的主意。 (见std::vector
  • 您正在使用new,这是一个非常糟糕的选择。您也不遵守零规则,因此您的 Vector 将在即使是简单的情况下也会中断。只需使用std::vector
  • @TheDude 好的,这似乎是个好主意。其实我不想用c-style。但是,如何在不使用循环初始化内部 std :: 数组 的情况下通过构造函数传递 std :: 数组?它与模板和参数包的存在方式不同吗?

标签: c++ arrays c++11 constructor variadic-templates


【解决方案1】:

传递一个像可变参数模板这样的数组不是解决方案。可变参数模板用于将 N 个参数传递给类/函数。然而你只传递了一个参数!

我建议你去

我建议你使用数组引用,它在所有 C++ 版本中都可用:

class Vector {
public:
    long double* elements;
public:
    template<std::size_t size>
    Vector(long double (&array)[size]) {
        elements = new long double[size];
        for(int i = 0; i < size; i++) {
            elements[i] = array[i];
        }
    };

    virtual ~Vector() {
        delete []elements;
    }
};

顺便说一句,如果可以,请使用矢量。我非常怀疑这个自定义向量类是否与std::vector 一样高效(没有几何增长或优化的复制和移动)

【讨论】:

    【解决方案2】:

    我不确定这是否能回答您的问题,但我会给您一个一般性建议: 我猜您想将自己的逻辑封装到向量中。 标准库向量非常先进,您应该使用它,而不是浪费时间编写自己的低级代码。你可以更专注于你需要的逻辑。

    您可以定义自己的向量,并且仍然使用 std::vector 的优势来构造您的 Vector 对象。 例如继承:

    template<typename T>
    class Vector : public std::vector<int>
    {
       // here comes the implementation of your interface.
    }
    

    或作文:

    template<typename T>
    class Vector {
    private:
        std::vector<T> elems;
    }
    

    在组合的情况下,你必须定义你需要的构造函数。

    在这两种情况下,您都可以使用自己的 Vector,如下所示:

    Vector<double> vec1(10);         // construct vector with 10 double's each = 0
    Vector<double> vec2(10, 5);      // construct vector with 10 double's each = 5
    Vector<double> vec3{1,2,3,4};    // using initializer list
    Vector<double> vec4(somecontainer.begin(), somecontainer.end());   // construct vector by copying elemts from some other container 
    

    等等

    正如您在 std::vector 中看到的那样,您将获得构建自己的 Vector 对象所需的所有好处。

    【讨论】:

    • 我喜欢您使用的第二种方法(我更喜欢封装而不是继承)以及创建 Vector 对象的方式,该对象直接将 N 个值传递给构造函数。在我的情况下,由于我不需要在构造 Vector 后向内部类容器添加元素,是否可以使用 std::arraynot std::vector?在这两种情况下,现在我都可以在我的 Vector 类中删除 newdestructor。但是,如何填充内部 Vector 类 std::array 容器而不使用构造函数中的 for 循环 使用封装?
    • std::array 是一个聚合类型,这意味着它没有构造函数。我已经为您提供了 2 个使用 std::array 进行继承和组合的示例,初始化时没有 for 循环(当这是您的问题时):wandbox.org/permlink/af2xWXg9AOkm1G1h
    • 非常感谢您提供的更多示例!在进行了一些测试(并且 std::array 大小出现了一些问题)之后,我决定按照您的建议使用带有封装的 std::vector,如 main your回答! :)
    【解决方案3】:

    根据你的定义

     template<typename... Args> Vector(Args... args);
    

    你想以这种方式使用这个构造函数:

     Vector vector = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
    

    如果您将构造函数的定义修改为:

    template<typename... Args>
    Vector(Args... args){
        constexpr int size = sizeof...(Args);
        elements = new long double[size]{static_cast<long double>(args)...};
    }
    

    请注意,这种用法不是好的做法,您应该正常使用std 容器并避免使用new 运算符。

    【讨论】:

    • 我不想使用 new 运算符;所以 std 容器是受欢迎的。我想知道是否可以在我的 Vector 类中使用 std::array :主要思想是 删除析构函数不使用 for 循环 在构造函数中填充内部 std::array 容器
    • std::array 需要在编译时知道元素个数,如果你直接放在你的类中,你的类需要有一个模板参数来表示它的大小。但总而言之,为什么不使用 std::vector 呢?它满足您提到的所有要求。通常你不需要创建一个名为Vector的类。
    • 这个类被命名为 Vector,因为我使用它封装在 2DVector、3DVector 和 4DVector 类中。所以 Vector 将是一个通用类,然后被其他人专门化。我问的是 std::array 因为我只需要一个在创建和填充后无法更改其大小的容器。在我传递大小的地方有一个带有模板参数的类不是问题。你认为在这种情况下 std::vector 是否也比 std::array 更好?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-16
    • 2016-09-12
    相关资源
    最近更新 更多