c++ - 如何从(嵌套的)std::initializer_list 确定大小?

标签 c++ arrays c++11 initializer-list

C++ 的新手并试图围绕 initializer_list 进行思考。

我正在创建一个 Matrix 类,它可以有效地存储 double 值的二维数组。我没有在结构层面上了解该项目。好吧,我们创建了一个 Matrix 类,它本质上存储了一个二维数组数据。但是它需要能够存储任意大小的数组,所以它必须使用动态分配的数组。但是 std::array 是不允许的。

我不知道如何访问 i_list 中的项目。如果他们像这样传入

Matrix a = {{1, 2}, {3, 4}};

然后根据我看到的文档,我在构造函数中与该信息交互的唯一选择是 list.begin() ,它指向 {1, 2} 和​​ list.end() ,它指向{3,4}

std::vector 和 std::array 被项目描述禁止,非动态数组显然不能为大小取变量。

那么我如何让它能够读取任何大小的矩阵,以及如何从我的 i_list 中获取这些值并将它们存储到非动态的东西中?

我在想像

Matrix::Matrix(const initializer_list & list) {
    double * mat[/*somehow find out size without dynamic allocation*/];
    for (double* i : mat) {
        *i = list[i]; //not how i_list works apparently
    }
}

项目描述说: 您不得为该项目使用诸如 std::array、std::vector、std::list 等库类。您必须使用动态分配的数组在内部实现 Matrix 类

最佳答案

initializer_list 是非常便宜的 [references to] 临时对象的容器。

您可以像处理数组一样遍历它们。此外,它们还有一个 size() 成员,因此您可以查询它们的尺寸。

这是将“2d”initializer_list 传递给函数(很容易成为构造函数)的示例:

#include <initializer_list>
#include <iostream>


using list_of_doubles = std::initializer_list<double>;
using list_of_list_of_doubles = std::initializer_list<list_of_doubles>;

void info(list_of_list_of_doubles lld)
{
    std::cout << "{\n";
    for (auto& ld : lld) {
        std::cout << "  {";
        auto sep = " ";
        for (auto& d : ld) {
            std::cout << sep << d;
            sep = ", ";
        }
        std::cout << " }\n";
    }

    std::cout << "}\n";
}

int main()
{
    info({
        { 1,2,3 },
        { 4.0, 5.0, 6.0 }
    });
}

预期输出:

{
  { 1, 2, 3 }
  { 4, 5, 6 }
}

Printing out the contents of the list is pretty simple, but what if I want to save them non-dynamically? I'm making a class constructor, and I want to have access to that data.

好的,所以要求类中的存储是非动态的(即固定大小)。

我将做一些假设:

  1. 假设目标类是一个 3x3 矩阵
  2. initializer_list 中任何未指定的项目都应假定为零。
  3. 传入超过 3 行或 3 列是逻辑错误,应该引发异常

这是(许多)方法之一:

#include <initializer_list>
#include <iostream>
#include <stdexcept>
#include <algorithm>


using list_of_doubles = std::initializer_list<double>;
using list_of_list_of_doubles = std::initializer_list<list_of_doubles>;

struct matrix
{
    matrix(list_of_list_of_doubles lld)
    : _storage {}
    {
        if (lld.size() > 3)
            throw std::invalid_argument("too many rows");
        auto row_idx = std::size_t { 0 };
        for (auto& row : lld) {
            if (row.size() > 3)
                throw std::invalid_argument("too many columns");
            std::copy(std::begin(row), std::end(row), std::begin(_storage[row_idx]));
            ++row_idx;
        }
    }

    double _storage[3][3];
};

std::ostream& operator<<(std::ostream& os, const matrix& m)
{
    std::cout << "{\n";
    for (auto& ld : m._storage) {
        std::cout << "  {";
        auto sep = " ";
        for (auto& d : ld) {
            std::cout << sep << d;
            sep = ", ";
        }
        std::cout << " }\n";
    }

    return std::cout << "}";
}

int main()
{
    matrix m({
        { 1,2,3 },
        { 4.1, 5.2, 6.3 },
        { 2.01, 4.5 }  // ,0
    });
    std::cout << m << std::endl;

}

but I wanted a dynamically-sized 2-d array...

哦,那继续吧...

#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>


using list_of_doubles = std::initializer_list<double>;
using list_of_list_of_doubles = std::initializer_list<list_of_doubles>;

std::size_t total_extent(const list_of_list_of_doubles& lld)
{
    return std::accumulate(std::begin(lld), std::end(lld), std::size_t(0),
                           [](auto tot, auto& container) {
                               return tot + container.size();
                           });

}

struct matrix
{
    using value_storage = std::unique_ptr<double[]>;
    using index_storage = std::unique_ptr<std::size_t>;

    matrix(list_of_list_of_doubles lld)
    : _total_extent { total_extent(lld) }
    , _rows { lld.size() }
    , _indecies { new std::size_t[_rows] }
    , _storage { new double [_total_extent] }
    {
        auto istorage = _storage.get();
        auto iindex = _indecies.get();
        for (auto& row : lld) {
            *iindex++ = istorage - _storage.get();
            istorage = std::copy(std::begin(row), std::end(row), istorage);
        }
    }

    std::size_t rows() const {
        return _rows;
    }

    const double* column(std::size_t row) const {
        return std::addressof(_storage[_indecies[row]]);
    }

    std::size_t column_size(std::size_t row) const {
        return row == _rows - 1
        ? _total_extent - _indecies[row]
        : _indecies[row + 1] - _indecies[row];
    }

    std::size_t _total_extent, _rows;
    std::unique_ptr<std::size_t[]> _indecies;
    std::unique_ptr<double[]> _storage;
};

std::ostream& operator<<(std::ostream& os, const matrix& m)
{
    std::cout << "{\n";
    for (std::size_t row = 0 ; row < m.rows() ; ++row) {
        std::cout << "  {";
        auto sep = " ";
        for (std::size_t col = 0 ; col < m.column_size(row) ; ++col) {
            std::cout << sep << m.column(row)[col];
            sep = ", ";
        }
        std::cout << " }\n";
    }

    return std::cout << "}";
}

int main()
{
    matrix m({
        { 1,2,3 },
        { 4.1, 5.2, 6.3 },
        { 2.01, 4.5 }  // ,0
    });
    std::cout << m << std::endl;

}

关于c++ - 如何从(嵌套的)std::initializer_list 确定大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38292224/

相关文章:

c++ - g++ : should --std option change which STL/stdlib my code uses?

c++ - 如何使用 CURL 查看网页上是否有特定文本?

php - 如何让 in_array() 不区分大小写?

c - 数组和结构体

python - 在n维数组中迭代修改基于数组的索引元素

c++ - C++/gcc/linux 中的 Continuations/Coroutines/Generators

c++ - 如何使用QtSingleApplication bt的so文件?

c++ - 仅在函数中设置静态变量一次

c++ - 使用引用运算符 (&) 将随机值分配给矩阵

c++ - C++中的多线程: The correct way to join threads