显式构造函数和嵌套的初始化列表

Ext3h

以下代码可使用大多数现代C ++ 11兼容编译器(GCC> = 5.x,Clang,ICC,MSVC)成功编译。

#include <string>

struct A
{
        explicit A(const char *) {}
        A(std::string) {}
};

struct B
{
        B(A) {}
        B(B &) = delete;
};

int main( void )
{
        B b1({{{"test"}}});
}

但是,为什么要首先编译它?列出的编译器如何解释该代码?

为什么MSVC可以不使用而进行编译B(B &) = delete;,而其他3个编译器都需要它?

当我删除复制构造函数其他签名时,为什么它在MSVC以外的所有编译器中都失败了B(const B &) = delete;

编译器是否都选择相同的构造函数?

为什么Clang会发出以下警告?

17 : <source>:17:16: warning: braces around scalar initializer [-Wbraced-scalar-init]
        B b1({{{"test"}}});
xskxzr

除了解释编译器的行为外,我将尝试解释该标准的内容。

主要例子

直接初始化b1{{{"test"}}},重载适用于选择最佳的构造B因为没有从{{{"test"}}}到的隐式转换B&(列表初始化器不是左值),所以构造函数B(B&)不可行。然后,我们专注于构造函数B(A),并检查它是否可行。

为了确定从{{{"test"}}}的隐式转换顺序A为简单起见,我将使用符号{{{"test"}}}-> A),重载分辨率适用于选择的最佳构造函数A,因此我们需要比较{{"test"}}->const char*{{"test"}}-> std::string(注意,括号的最外层已被省略)根据[over.match.list] / 1

当非聚合类类型T的对象被列表初始化,使得[dcl.init.list]指定根据本小节中的规则执行重载解析时,重载解析在两个阶段中选择构造函数:

  • 最初,候选函数是类T的初始化器列表构造函数([dcl.init.list])。

  • 如果找不到可行的初始化器列表构造函数,则再次执行重载解析,其中候选函数是T类的所有构造器,并且参数列表由初始化器列表的元素组成。

...在复制列表初始化中,如果选择了显式构造函数,则初始化格式错误。

请注意,无论指定符是什么,这里都考虑所有构造函数explicit

{{"test"}}->const char*根据[over.ics.list] / 10[over.ics.list] / 11不存在

否则,如果参数类型不是类:

  • 如果初始化列表中有一个本身不是初始化列表的元素,则...

  • 如果初始化列表没有元素...

除上面列举的情况外,在所有情况下均无法进行转换。

要确定{{"test"}}-> std::string,需要执行相同的过程,并且重载分辨率选择std::string类型为的参数的构造函数const char*

结果,{{{"test"}}}->A通过选择构造函数完成A(std::string)


变化

如果explicit被删除怎么办?

该过程不会改变。GCC将选择构造函数,A(const char*)而Clang将选择构造函数A(std::string)我认为这是GCC的错误。

如果初始化器中只有两层大括号b1怎么办?

注意{{"test"}}->const char*不存在,但{"test"}->const char*存在。因此,如果的初始化程序中只有两层括号,则选择b1构造函数A(const char*)是因为{"test"}->const char*{"test"}->更好std::string结果,在复制列表初始化(从中初始化A构造函数中的参数)选择了一个显式构造函数,然后该程序格式错误。B(A){"test"}

如果B(const B&)声明了构造函数怎么办?

请注意,如果B(B&)删除了声明,也会发生这种情况这次我们需要等效地比较{{{"test"}}}->A{{{"test"}}}->const B&{{{"test"}}}-> const B

为了确定{{{"test"}}}-> const B,采用上述过程。我们需要比较{{"test"}}->A{{"test"}}-> const B&注意:{{"test"}}-> [over.best.ics] / 4const B&不存在

但是,如果目标是

—构造函数的第一个参数,或者

—用户定义的转换函数的隐式对象参数

并且构造函数或用户定义的转换函数是

— [over.match.ctor],当参数是类复制初始化的第二步中的临时参数时,

— [over.match.copy],[over.match.conv]或[over.match.ref](在所有情况下),或

[over.match.list]的第二阶段,当初始值设定项列表恰好具有一个本身就是初始值设定项列表的元素,并且目标是类X的构造函数的第一个参数,并且转换为X或对CV X

不考虑用户定义的转换序列。

为了确定{{"test"}}-> A,再次采用上述过程。这几乎与我们在前面小节中讨论的情况相同。结果,A(const char*)选择了构造函数请注意,此处选择了构造函数来确定{{{"test"}}}-> const B,但实际上并不适用。尽管构造函数是显式的,但这是允许的。

结果,{{{"test"}}}->const B通过选择构造函数B(A),然后选择构造函数来完成A(const char*)现在{{{"test"}}}->A{{{"test"}}}->const B都是用户定义的转换序列,并且两者都不比另一个更好,因此的初始化b1是不明确的。

如果括号被大括号代替怎么办?

根据[over.best.ics] / 4(在上一小节中用引号引用),不考虑用户定义的转换{{{"test"}}}-> const B&因此,即使B(const B&)声明了构造函数,结果也与主要示例相同

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

向量构造函数对:初始化列表与显式构造

来自分类Dev

为什么显式声明的构造函数阻止使用C ++ 11初始化列表进行成员初始化?

来自分类Dev

具有成员初始化列表的显式副本构造函数中的空值

来自分类Dev

显式构造函数和std :: initializer_list初始化

来自分类Dev

如何在 g++-10 中结合基类显式构造函数和指定初始化?

来自分类Dev

如何在不显式调用显式构造函数的情况下初始化映射?

来自分类Dev

镖。子类和构造函数初始化器列表

来自分类Dev

列表初始化程序和可变参数构造函数

来自分类Dev

-Wreorder和构造函数初始化器列表

来自分类Dev

为什么在调用构造函数之前进行显式初始化

来自分类Dev

C ++ 11:带“ = {}”的类内初始化不适用于显式构造函数

来自分类Dev

我是否需要在构造函数中显式初始化std :: unique_ptr?

来自分类Dev

是否可以编写有助于复制初始化的显式构造函数?

来自分类Dev

如何为显式重载的构造函数启用副本初始化?

来自分类Dev

显式初始化没有默认构造函数的成员

来自分类Dev

类组合构造函数d必须显式初始化引用成员

来自分类Dev

错误:构造函数必须显式初始化引用成员

来自分类Dev

为什么在具有主构造函数的记录中需要显式的“ this”构造函数初始化器?

来自分类Dev

为什么可以在构造函数中使用成员初始化来满足显式构造函数的参数呢?

来自分类Dev

Kotlin和构造函数,初始化

来自分类Dev

基本/默认构造函数与构造函数初始化列表

来自分类Dev

使用父类构造函数初始化列表在嵌套类字段中设置值

来自分类Dev

如何避免在C ++中显式构造在初始化列表中继承的所有内容?

来自分类Dev

C ++在初始化列表之外显式调用父构造函数

来自分类Java

为什么要在所有构造函数中显式初始化空白的最终变量?

来自分类Dev

如何在定义附近使用显式的长度/值构造函数初始化向量成员变量?

来自分类Dev

Swift扩展和“元素”显式初始化

来自分类Dev

C ++中的初始化程序列表和类初始化。我有无参数构造函数,但仍必须使用初始化列表?

来自分类Dev

C ++ 11统一初始化:初始化列表和多参数构造函数之间的歧义?

Related 相关文章

  1. 1

    向量构造函数对:初始化列表与显式构造

  2. 2

    为什么显式声明的构造函数阻止使用C ++ 11初始化列表进行成员初始化?

  3. 3

    具有成员初始化列表的显式副本构造函数中的空值

  4. 4

    显式构造函数和std :: initializer_list初始化

  5. 5

    如何在 g++-10 中结合基类显式构造函数和指定初始化?

  6. 6

    如何在不显式调用显式构造函数的情况下初始化映射?

  7. 7

    镖。子类和构造函数初始化器列表

  8. 8

    列表初始化程序和可变参数构造函数

  9. 9

    -Wreorder和构造函数初始化器列表

  10. 10

    为什么在调用构造函数之前进行显式初始化

  11. 11

    C ++ 11:带“ = {}”的类内初始化不适用于显式构造函数

  12. 12

    我是否需要在构造函数中显式初始化std :: unique_ptr?

  13. 13

    是否可以编写有助于复制初始化的显式构造函数?

  14. 14

    如何为显式重载的构造函数启用副本初始化?

  15. 15

    显式初始化没有默认构造函数的成员

  16. 16

    类组合构造函数d必须显式初始化引用成员

  17. 17

    错误:构造函数必须显式初始化引用成员

  18. 18

    为什么在具有主构造函数的记录中需要显式的“ this”构造函数初始化器?

  19. 19

    为什么可以在构造函数中使用成员初始化来满足显式构造函数的参数呢?

  20. 20

    Kotlin和构造函数,初始化

  21. 21

    基本/默认构造函数与构造函数初始化列表

  22. 22

    使用父类构造函数初始化列表在嵌套类字段中设置值

  23. 23

    如何避免在C ++中显式构造在初始化列表中继承的所有内容?

  24. 24

    C ++在初始化列表之外显式调用父构造函数

  25. 25

    为什么要在所有构造函数中显式初始化空白的最终变量?

  26. 26

    如何在定义附近使用显式的长度/值构造函数初始化向量成员变量?

  27. 27

    Swift扩展和“元素”显式初始化

  28. 28

    C ++中的初始化程序列表和类初始化。我有无参数构造函数,但仍必须使用初始化列表?

  29. 29

    C ++ 11统一初始化:初始化列表和多参数构造函数之间的歧义?

热门标签

归档