C++:静态初始化器列表转换

huangapple go评论73阅读模式
英文:

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&lt;double&gt; 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&lt;double&gt;(__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&lt;int&gt; kInitList{1, 2, 3};
  // other stuff.
}

Gets tranformed to:

void foo() {
  static const int __a[3] = {1, 2, 3};
  static const std::initializer_list&lt;int&gt; kInitList(__a, __a+3);
  // other stuff.
}

The backing array also becomes static (along with const).

答案1

得分: 3

用于 std::initializer_list 的支持数组在 [dcl.init.list]/5&ndash;6 中描述:

> std​::​initializer_list&lt;E&gt; 类型的对象是从初始化列表中构造的,就好像实现生成并实现了类型为“数组,包含 Nconst E”的 prvalue([conv.rval]),其中 N 是初始化列表中的元素数量。该数组的每个元素都与初始化列表的相应元素进行复制初始化,并构造 std​::​initializer_list&lt;E&gt; 对象以引用该数组。[...]
>
> 该数组的生存期与任何其他临时对象相同([class.temporary]),只是用该数组初始化 initializer_list 对象会像将引用绑定到临时对象一样扩展数组的生存期。[...]

因此,当 initializer_list 具有静态存储期时,数组并非完全具有静态存储期。它是一个临时对象,其生存期延伸到具有静态存储期的引用的生存期。

未解决的核心问题 CWG1634 询问临时对象是否具有存储期,以及如果是这样,存储期是什么。意图似乎是,生存期延伸到某个引用的临时对象“继承”该引用的存储期。因此,也许最终我们将能够明确地说该数组确实具有静态存储期。

尽管如此,该数组仍然是一个临时对象。这意味着,例如,不能将其地址用作模板参数,就像如果它真的被定义为静态变量一样。[规则链接]

英文:

The backing array for a std::initializer_list is described in [dcl.init.list]/5&ndash;6:

> An object of type std​::​initializer_list&lt;E&gt; 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&lt;E&gt; 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]

huangapple
  • 本文由 发表于 2023年5月18日 06:35:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76276609.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定