使用 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
我需要一个 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
的名称暗示了某种用途。
我也考虑过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