【问题标题】:How do you pass fixed sized initializer lists of initializer lists through function parameters in C++?如何通过 C++ 中的函数参数传递固定大小的初始值设定项列表的初始值设定项列表?
【发布时间】:2020-05-23 15:45:54
【问题描述】:

我正在创建一个矩阵类,我希望用户能够像这样实例化矩阵:

Matrix<float, 2, 2> mat = { { 10, 20 }, { 30, 40 } };

我的 Matrix 类是这样定义的:

template<typename T, unsigned int ROWS, unsigned int COLS>
class Matrix
{
public:
    Matrix(std::array<std::array<T, ROWS>, COLS> matrix)
    {
        // ...
    }
    // ...
};

但是,当我尝试实例化矩阵时,就像我在上面所做的那样,我从编译器收到“无法转换”错误。我不想使用初始值设定项列表,因为如果用户以错误的顺序定义矩阵,我希望触发编译时错误。有谁为什么这不起作用?如果是的话,还有其他选择吗?

【问题讨论】:

  • 问题是std::array 使用聚合初始化(因此可能需要/需要额外的大括号),但是您使用复制/移动构造函数进行了模棱两可的调用:-/
  • 谢谢@Jarod42,那有什么办法吗?

标签: c++ arrays matrix initializer-list


【解决方案1】:

std::array 只支持聚合初始化。通过使用Matrix&lt;float, 2, 2&gt; mat = { ... }; 语法,您请求复制初始化,std::array 只是拒绝。请注意,通过将std::array&lt;std::array&lt;...&gt;...&gt; 作为构造函数参数,您可以使用以下初始化语法:Matrix&lt;float, 2, 2&gt; mat{{ 10, 20, 30, 40 }};

最有可能的是,您想要的是 std::initializer_list 参数。

如果你想让你的类表现得像std::array 但有两个维度,你不妨做std::array 的实现,它没有构造函数并公开内部成员:

template<typename T, unsigned int ROWS, unsigned int COLS>
class Matrix
{
public:
    T elements_[ROWS][COLS];
};

这里是 stdlibc++ (gcc) 的实现:https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/array#L93。注意_M_elems 的声明是公开的(array 在这里是struct)。这意味着如果您知道您正在使用标准库的这个特定实现,您可以直接访问_M_elems,但这也是使aggregate initialization 工作的唯一方法。

这也意味着您允许使用语法Matrix&lt;float, 2, 2&gt; mat2 = { 10, 20, 40, 40 };

Demo

【讨论】:

  • 如前所述,std::initializer_list 的问题是,如果矩阵的顺序不正确,我希望触发编译时错误。
  • @MaximV 我添加了另一个您可能感兴趣的选项。
【解决方案2】:

问题是std::array 使用聚合初始化(因此可能需要/需要额外的大括号),但是您可能会使用复制/移动构造函数进行模棱两可的调用:-/

以下编译:

template <std::size_t COLS, std::size_t ROWS>
struct Matrix
{
    Matrix(const std::array<std::array<float, COLS>, ROWS>&) {}
    //Matrix(const std::vector<std::vector<float>>&) {}
};

int main() {
    [[maybe_unused]]Matrix<3, 2> m1 = std::array{ std::array{1.f, 2.f, 3.f}, std::array{1.f, 2.f, 3.f}};
    [[maybe_unused]]Matrix<3, 2> m2 ({{ {{1.f, 2.f, 3.f}}, {{1.f, 2.f, 3.f}}}});
    //[[maybe_unused]]Matrix<3, 2> m3 ({ {1.f, 2.f, 3.f}, {1.f, 2.f, 3.f}}); // OK vector
}

Demo

【讨论】:

    【解决方案3】:

    这似乎有效...

    template<typename T, unsigned int ROWS, unsigned int COLS>
    class Matrix
    {
    public:
        Matrix(const std::array<T, ROWS> (&matrix)[COLS]) {
            // ... 
        }
    };
    
    int main() {
        Matrix<float, 2, 2> mat = {{ { 10, 20 }, { 40, 40 } }};
    }
    

    虽然错误消息在失败时非常糟糕,并且只有在您提供太多行或列时才会失败!...与std::array&lt;int,3&gt; a = {1,2};有效的原因相同...

    编辑:

    Matrix(const T (&matrix)[COLS][ROWS]) {}
    

    也是有效的

    【讨论】:

    • 谢谢@JakeSchmidt,这很好用,唯一的问题是我不明白语法是如何工作的,因为我尝试使用Matrix(const std::array&lt;unsigned, ROWS&gt;[COLS]&amp; matrix),但它不起作用
    • 另外,是否可以传递一个 c++ 数组,例如:Matrix(T[COLS][ROWS] matrix)?
    • @MaximV 我不这么认为
    猜你喜欢
    • 2019-02-17
    • 1970-01-01
    • 2017-03-07
    • 2012-12-24
    • 1970-01-01
    • 2021-10-29
    • 2016-01-22
    • 2020-12-04
    • 1970-01-01
    相关资源
    最近更新 更多