Explicit copy constructor and uniform initialization

不羁岁月 提交于 2019-12-04 22:19:54

You've encountered a case that was addressed by the resolution of Core issue 1467 immediately after C++14 was finalized.

Let's first note that class foo is an aggregate. Your code is doing direct-list-initialization for foo. The rules for list-initialization are in [8.5.4p3].

In C++14 (quoting from N4140, the working draft closest to the published standard), the paragraph above started with:

List-initialization of an object or reference of type T is defined as follows:

  • If T is an aggregate, aggregate initialization is performed (8.5.1).

[...]

So, if your class is an aggregate, the compiler tries to do aggregate initialization, which fails.

This was recognized as a problem, and fixed in the working draft. Quoting from the current version, N4527, the above-mentioned paragraph now starts with:

List-initialization of an object or reference of type T is defined as follows:

  • If T is a class type and the initializer list has a single element of type cv U, where U is T or a class derived from T, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).
  • Otherwise, if T is a character array and the initializer list has a single element that is an appropriately typed string literal (8.5.2), initialization is performed as described in that section.
  • Otherwise, if T is an aggregate, aggregate initialization is performed (8.5.1).

[...]

Your example now falls within the case described by the first bullet point, and foo is direct-list-initialized using the defaulted copy constructor (regardless of whether it's explicit, since it's direct initialization).

That is... if the compiler implements the resolution in the defect report.

  • GCC 5.2.0 (and 6.0.0 trunk) seems to do so, but seems to have a bug related to that explicit.
  • Clang 3.6.0 doesn't, but 3.8.0 trunk does, and does it correctly (explicit doesn't matter).
  • MSVC 14 does, but IntelliSense in the IDE doesn't (squiggles under bar - looks like the EDG compiler used by IntelliSense wasn't updated either).

Update: Since this answer was written, the working draft has been further amended in a couple of ways that are relevant to the example in the question and the explanation above:

  • CWG 2137 indicates that the first bullet in the paragraph quoted above went a bit too far by applying that exception to all class types (the issue notes contain a relevant example). The beginning of the bullet now reads:
    • If T is an aggregate class and [...]
  • The resolution of CWG 1518 contained in paper P0398R0 indicates that classes that declare an explicit constructor (even defaulted) are no longer aggregates.

This doesn't change the fact that, after all the changes are implemented, the example in the question is intended to work, with or without the explicit; it's just worth knowing that the underlying mechanisms that make it work have changed slightly.

Note that all these changes are resolutions of defect reports, so they're supposed to apply when compilers are in C++14 and C++11 modes as well.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!