“明确”的目的是什么?对于默认构造函数?
我最近注意到 C++0x 中的一个类需要显式默认构造函数。但是,我无法想出可以隐式调用默认构造函数的方案。这似乎是一个毫无意义的说明符。我想也许它会禁止 Class c;
而支持 Class c = Class();
但事实似乎并非如此。
C++11 FCD 中的一些相关引用,因为它对我来说更容易导航[C++03 中存在类似的文本,如果不在相同的地方]
12.3.1.3 [class.conv.ctor]
默认构造函数可以是显式构造函数;这样的构造函数将用于执行默认初始化或值初始化(8.5)。
它继续提供显式默认构造函数的示例,但它只是模仿我上面提供的示例。
8.5.6 [decl.init]
默认初始化 T 类型的对象意味着:
——如果 T 是一个(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是格式错误的);
8.5.7 [decl.init]
对 T 类型的对象进行值初始化意味着:
——如果 T 是一个(可能是 cv 限定的)类类型(第 9 条),具有用户提供的构造函数 (12.1),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数);
在这两种情况下,标准都要求调用默认构造函数。但如果默认构造函数是非显式的,就会发生这种情况。为了完整起见:
8.5.11 [decl.init]
如果没有为对象指定初始化程序,则该对象将被默认初始化;
据我所知,这只留下了没有数据的转换。这没有道理。我能想到的最好的办法是:
void function(Class c);
int main() {
function(); //implicitly convert from no parameter to a single parameter
}
但显然这不是 C++ 处理默认参数的方式。还有什么会使 explicit Class();
的行为与 Class();
不同?
生成此问题的具体示例是 std::function [20.8.14.2 func.wrap.func]。它需要多个转换构造函数,其中没有一个被标记为显式,但默认构造函数是显式的。
I recently noticed a class in C++0x that calls for an explicit default constructor. However, I'm failing to come up with a scenario in which a default constructor can be called implicitly. It seems like a rather pointless specifier. I thought maybe it would disallow Class c;
in favor of Class c = Class();
but that does not appear to be the case.
Some relevant quotes from the C++11 FCD, since it is easier for me to navigate [similar text exists in C++03, if not in the same places]
12.3.1.3 [class.conv.ctor]
A default constructor may be an explicit constructor; such a constructor will be used to perform default-initialization or value initialization (8.5).
It goes on to provide an example of an explicit default constructor, but it simply mimics the example I provided above.
8.5.6 [decl.init]
To default-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
8.5.7 [decl.init]
To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
In both cases, the standard calls for the default constructor to be called. But that is what would happen if the default constructor were non-explicit. For completeness sake:
8.5.11 [decl.init]
If no initializer is specified for an object, the object is default-initialized;
From what I can tell, this just leaves conversion from no data. Which doesn't make sense. The best I can come up with would be the following:
void function(Class c);
int main() {
function(); //implicitly convert from no parameter to a single parameter
}
But obviously that isn't the way C++ handles default arguments. What else is there that would make explicit Class();
behave differently from Class();
?
The specific example that generated this question was std::function
[20.8.14.2 func.wrap.func]. It requires several converting constructors, none of which are marked explicit, but the default constructor is.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这声明了一个显式默认构造函数:
如果没有参数,如以下示例所示,则显式默认构造函数是多余的。
在一些 C++0x 草案中(我相信是 n3035),它通过以下方式产生了影响:
但是在 FCD 中,它们 改变了这一点(不过,我怀疑他们没有考虑到这个特殊原因),因为所有三种情况都值-初始化相应的对象。值初始化不会执行重载解析舞蹈,因此不会在显式构造函数上失败。
This declares an explicit default constructor:
In case there is no parameter, like in the following example, the
explicit
is redundant.In some C++0x draft (I believe it was n3035), it made a difference in the following way:
But in the FCD, they changed this (though, I suspect that they didn't have this particular reason in mind) in that all three cases value-initialize the respective object. Value-initialization doesn't do the overload-resolution dance and thus won't fail on explicit constructors.
除非另有明确说明,否则以下所有标准参考均指 N4659:2017 年 3 月帖子-Kona 工作草案/C++17 DIS。
(此答案特别关注没有参数的显式默认构造函数)
案例 #1 [ >C++11 到 C++20]:非聚合的空
{}
复制列表初始化禁止使用显式默认构造函数受 [over.match.list]/1 [强调 我的]:
copy-list-initialization,带有空的braced-init-list
{}
,用于非聚合禁止使用显式默认构造函数;例如:尽管上面的标准引用是指 C++17,但这同样适用于 C++11、C++14 和 C++20。
情况#2 [仅限 C++17]:具有用户声明的构造函数且标记为
显式
的类类型不是聚合[dcl.init.aggr]/1 添加在 C++14 之间进行了一些更新和 C++17,主要是允许聚合从基类公开派生,但有一些限制,但也禁止聚合的
显式
构造函数[强调我的]:自 P1008R1 起(禁止使用用户声明的构造函数进行聚合)(已为 C++20 实现),我们可能不再为聚合声明构造函数。然而,仅在 C++17 中,我们就有一个特殊的规则,即用户声明的(但不是用户提供的)构造函数是否被显式标记决定了类类型是否是聚合。例如,类类型
在 C++11 到 C++20 中是聚合/非聚合,如下所示:
Foo
&Bar
都是聚合Foo
&Bar
都是聚合Foo
是聚合(Bar
有一个显式
构造函数)Foo
或Bar
都不是聚合(两者都有用户声明的构造函数)Unless explicitly stated otherwise, all standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.
(This answer focus specifically on explicit default constructors which have no parameters)
Case #1 [C++11 through C++20]: Empty
{}
copy-list-initialization for non-aggregates prohibits use of explicit default constructorsAs governed by [over.match.list]/1 [emphasis mine]:
copy-list-initialization with an empty braced-init-list
{}
for non-aggregates prohibits use of explicit default constructors; e.g.:Albeit the standard quote above refers to C++17, this likewise applies for C++11, C++14 and C++20.
Case #2 [C++17 only]: A class type with a user-declared constructor that is marked as
explicit
is not an aggregate[dcl.init.aggr]/1 added was updated some between C++14 and C++17, mainly by allowing an aggregate to derive publicly from a base class, with some restrictions, but also prohibiting
explicit
constructors for aggregates [emphasis mine]:As of P1008R1 (Prohibit aggregates with user-declared constructors), which has been implemented for C++20, we may no longer ever declare constructors for aggregates. In C++17 alone, however, we had the peculiar rule that whether a user-declared (but not user-provided) constructor was marked explicit decided whether the class type was an aggregate or not. E.g. the class types
were aggregates/not aggregates in C++11 through C++20 as follows:
Foo
&Bar
are both aggregatesFoo
&Bar
are both aggregatesFoo
is an aggregate (Bar
has anexplicit
constructor)Foo
orBar
are aggregates (both has user-declared constructors)