英文:
C++: static initializer_list transformation
问题
C++标准规定,初始化列表将以以下方式转换:
struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };
初始化将以大致等效于此方式实现:
const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));
假设实现可以使用一对指针构造initializer_list对象。
可以合理地假设static const initializer_list
将会有以下类型的转换:
void foo() {
static const std::initializer_list<int> kInitList{1, 2, 3};
// 其他内容。
}
被转换为:
void foo() {
static const int __a[3] = {1, 2, 3};
static const std::initializer_list<int> kInitList(__a, __a+3);
// 其他内容。
}
支持数组也变成了static
(连同const)。
英文:
C++ standard defines that initializer_list will be transformed in the following manner:
struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };
The initialization will be implemented in a way roughly equivalent to this:
const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));
assuming that the implementation can construct an initializer_list object with a pair of pointers.
Is it fair to assume that static const initializer_list
will have the following type of transformation?
void foo() {
static const std::initializer_list<int> kInitList{1, 2, 3};
// other stuff.
}
Gets tranformed to:
void foo() {
static const int __a[3] = {1, 2, 3};
static const std::initializer_list<int> kInitList(__a, __a+3);
// other stuff.
}
The backing array also becomes static
(along with const).
答案1
得分: 3
用于 std::initializer_list
的支持数组在 [dcl.init.list]/5–6 中描述:
> std::initializer_list<E>
类型的对象是从初始化列表中构造的,就好像实现生成并实现了类型为“数组,包含 N 个 const E
”的 prvalue([conv.rval]),其中 N 是初始化列表中的元素数量。该数组的每个元素都与初始化列表的相应元素进行复制初始化,并构造 std::initializer_list<E>
对象以引用该数组。[...]
>
> 该数组的生存期与任何其他临时对象相同([class.temporary]),只是用该数组初始化 initializer_list
对象会像将引用绑定到临时对象一样扩展数组的生存期。[...]
因此,当 initializer_list
具有静态存储期时,数组并非完全具有静态存储期。它是一个临时对象,其生存期延伸到具有静态存储期的引用的生存期。
未解决的核心问题 CWG1634 询问临时对象是否具有存储期,以及如果是这样,存储期是什么。意图似乎是,生存期延伸到某个引用的临时对象“继承”该引用的存储期。因此,也许最终我们将能够明确地说该数组确实具有静态存储期。
尽管如此,该数组仍然是一个临时对象。这意味着,例如,不能将其地址用作模板参数,就像如果它真的被定义为静态变量一样。[规则链接]
英文:
The backing array for a std::initializer_list
is described in [dcl.init.list]/5–6:
> An object of type std::initializer_list<E>
is constructed from an initializer list as if the implementation generated and materialized ([conv.rval]) a prvalue of type "array of N const E
”, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list<E>
object is constructed to refer to that array. [...]
>
> The array has the same lifetime as any other temporary object ([class.temporary]), except that initializing an initializer_list
object from the array extends the lifetime of the array exactly like binding a reference to a temporary. [...]
So when the initializer_list
has static storage duration, it's not quite true that the array is declared with static storage duration too. It's a temporary object whose lifetime is extended to that of a reference with static storage duration.
Unresolved core issue CWG1634 asks whether temporary objects have storage duration and, if so, what that storage duration is. The intent seems to be that a temporary object whose lifetime is extended to that of some reference "inherits" that reference's storage duration. So perhaps eventually we will be able to say definitively that the array really does have static storage duration.
Nevertheless, the array is still a temporary object. That means, for example, that you can't use its address as a template argument the way you could if it were really defined as a static variable. [Link to rule]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论