【问题标题】:Which constructor is getting called for below string code?下面的字符串代码调用了哪个构造函数?
【发布时间】:2021-09-01 21:50:59
【问题描述】:

我在阅读 c++ 入门时遇到了一个向量列表初始化示例,其中作者提到如果无法进行列表初始化,则编译器会寻找其他方法来初始化对象。下面是一个字符串向量的例子。

vector<string> v8{10, "hi"};

这将创建一个包含 10 个元素的向量,其值为“hi”。我认为这是因为列表初始化依赖于下面的构造函数来创建向量。

vector( size_type count, const T& value, const Allocator& alloc = Allocator());

我为 String 尝试过类似的列表初始化

std::string s1{10, 'c'};

我期待它创建一个字符串“cccccccccc”,因为它有一个可用的构造函数

basic_string( size_type count, CharT ch, const Allocator& alloc = Allocator() );

但它只打印“c”?这里使用的是哪个字符串构造函数?

【问题讨论】:

  • 它实际上打印了"\nc"。注意到不一样的东西了吗?

标签: c++ c++11 constructor list-initialization stdinitializerlist


【解决方案1】:

constructor 获取 std::initiazer_list 被调用。

constexpr basic_string( std::initializer_list<CharT> ilist,
                        const Allocator& alloc = Allocator() );

10 是一个int,可以隐式转换为char,并且std::initializer_list&lt;char&gt; 可以从{10, 'c'} 构造为包含两个chars,第一个具有ASCII 值10,第二个是c

另一方面,对于std::vector&lt;std::string&gt;{10, "hi"} 不能用于构造std::initializer_list&lt;std::string&gt;,因为10 不能转换为std::string,那么采用std::initializer_list&lt;std::string&gt; 的构造函数就不会是用过。

【讨论】:

    【解决方案2】:

    这里开始起作用的是direct-list-initialization 的规则,它的语法为

    T object { arg1, arg2, ... };
    

    这里,在std::string s{10, 'c'}的情况下,上述语法中的Tstd::string,适用的规则是

    否则,将分两个阶段考虑 T 的构造函数:所有 将 std::initializer_list 作为唯一参数的构造函数,或 如果其余参数具有默认值,则作为第一个参数, 被检查,并通过重载决议对一个单一的匹配 std::initializer_list 类型的参数

    因为有一个 std::string 的构造函数,它接受一个初始值设定项列表,其他参数作为默认值,即 constructor (9)

    basic_string( std::initializer_list<CharT> ilist,
                  const Allocator& alloc = Allocator() );
    

    由于10 可以隐式转换为char,因此参与此解析,您得到的是std::initializer_list&lt;char&gt;{'\n', 'c'} 2 个字符。


    std::vector&lt;std::string&gt; v{10. "hi"} 的情况下,T 在上面提到的direct-list-initialization 的语法中是std::vector&lt;std::string&gt;

    现在,由于10 无法隐式转换为std::string,因此无法构造这样的std::initializer_list&lt;std::string&gt;,因此direct-list-initialization 的下一个替代方案是

    如果前一个阶段没有产生匹配,T的所有构造函数 参与针对一组参数的重载决议 由支撑初始化列表的元素组成,具有限制 只允许非缩小转换。

    这会产生与constructor 3的匹配

    explicit vector( size_type count,
                     const T& value = T(),
                     const Allocator& alloc = Allocator());
    

    因为这两种转换都不是非缩小的。


    现在来看看您想要使用 std::string s{10, 'c'} 实现的目标,这应该使用 std::string s(10, c) 来完成,其中不涉及 list-initialization

    std::string s1{10, 'c'}, s2(10, 'c');
    std::cout<<'['<<s1<<']'<<'['<<s2<<']'<<'\n';
    

    输出:

    [
    c][cccccccccc]
    

    请注意,打印s1 会在c 之前生成一个新行,因为它实际上是['\n', 'c'],而s2 正是您所期望的,即10 个c 字符。

    【讨论】:

      猜你喜欢
      • 2016-09-11
      • 2019-06-27
      • 2017-08-10
      • 1970-01-01
      • 2013-05-14
      • 2023-03-30
      • 1970-01-01
      • 2018-04-01
      相关资源
      最近更新 更多