使用 std::initializer_list[] 作为可变长度列表的常量列表

Using std::initializer_list[] as const list of lists of varying length

我需要一个 static const list of varying length (of QPointF from Qt) 我直接在我的代码中初始化(见下文),并且稍后仅以只读方式使用。

我首先使用 const std::vector<QPointF>[],但后来我发现我可以只使用 const std::initializer_list<QPointF>[] 来代替(甚至需要 const 吗?)。

static const std::initializer_list<QPointF> points[6] = {
        { { 0.50f, 0.50f } },
        { { 0.25f, 0.25f }, { 0.75f, 0.75f } },
        { { 0.25f, 0.25f }, { 0.50f, 0.50f }, { 0.75f, 0.75f } },
        { { 0.25f, 0.25f }, { 0.75f, 0.75f }, { 0.25f, 0.75f }, { 0.75f, 0.25f } },
        { { 0.25f, 0.25f }, { 0.75f, 0.75f }, { 0.50f, 0.50f }, { 0.25f, 0.75f }, { 0.75f, 0.25f } },
        { { 0.25f, 0.25f }, { 0.75f, 0.75f }, { 0.25f, 0.50f }, { 0.75f, 0.50f }, { 0.25f, 0.75f }, { 0.75f, 0.25f } },
    };

这是 std::initializer_list 的有效用法吗?对我来说这看起来像是一个 hack,可能是因为 std::iniatilizer_list 的名称暗示了某种用途。 post 的答案还提到初始化列表旨在用于初始化例如容器。

我也考虑过const std::array<...>[],但是所有内部列表的长度必须相同。

如果std::initializer_list不是这里的正确选择,那么如何正确地做到这一点。由于堆分配,备选方案 std::vector 感觉不对。

标准说

An object of type initializer_list provides access to an array of objects of type const E.

这并不意味着这些对象将专门用作初始化其他对象的临时对象,尽管这无疑是主要的预期用途。该标准实际上提供了一个将其正确用作变量的示例。

所以我看不出你所做的有什么问题。

了解您的编译器输出可以帮助您做出此决定。 std::initializer_list<>just a thin wrapper around an array of objects.

如果你真的需要静态常量数据,std::initializer_list<>[] 是完全有效的(只要你不介意使用它的访问语法而不是下标运算符,就像你在 std::array<>std::vector<>). Clang 8 将数组中的每个 initializer_list 降低为它自己的 QPointF 结构的固定长度数组。然后它用对它创建的 QPointF 数组的引用填充另一个数组:

// pseudo-C++ from Clang's generated output

QPointF RT1[1] = { { 0.50f, 0.50f } };
QPointF RT2[2] = { { 0.25f, 0.25f }, { 0.75f, 0.75f } };
QPointF RT3[3] = { { 0.25f, 0.25f }, { 0.50f, 0.50f }, { 0.75f, 0.75f } };
QPointF RT4[4] = { { 0.25f, 0.25f }, { 0.75f, 0.75f }, { 0.25f, 0.75f }, { 0.75f, 0.25f } };
QPointF RT5[5] = { { 0.25f, 0.25f }, { 0.75f, 0.75f }, { 0.50f, 0.50f }, { 0.25f, 0.75f }, { 0.75f, 0.25f } };
QPointF RT6[6] = { { 0.25f, 0.25f }, { 0.75f, 0.75f }, { 0.25f, 0.50f }, { 0.75f, 0.50f }, { 0.25f, 0.75f }, { 0.75f, 0.25f } };

// Reference array:
QPointF* points[6] = { RT1, RT2, RT3, RT4, RT5, RT6 };

访问列表中的单个值

(points[5].begin() + 3)->y

降低到本质上相当于

points[5][3].y
// alternatively:
(*(*(points + 5) + 3)).y
// which is actually:
(*(RT5 + 3)).y

std::initializer_list<>::begin() 的实现可能不同。)

因此,如果您不介意隐藏的取消引用或不同的语法风格,这很好。 (尽管您也会对数组或向量进行引用引用。)

尝试不同的优化级别并查看结果:https://godbolt.org/z/Vwjbp2