直接初始化与直接列表初始化(C++)

K.M*_*ier 9 c++ list-initialization c++17

DIRECT-VS COPY-INITIALIZATION
通过这个问题(它是直接初始化还是复制初始化?)我学到了直接初始化复制初始化之间的区别:

direct-initialization                   copy-initialization
-----------------------                 ---------------------

obj s("value");                         obj s = obj("value");
                                        obj s = "value";

obj s{"value"};                         obj s = {"value"};
                                        obj s = obj{"value"};
Run Code Online (Sandbox Code Playgroud)

为了完整起见,我在这里提到它.我对此页面的实际问题列在下一段>>

 
直接初始化与直接列表初始化
答案显示,在直接初始化的范畴内,可以在直接初始化直接列表初始化之间产生差异.

obj s("value");   // direct-initialization

obj s{"value"};   // direct-list-initialization
Run Code Online (Sandbox Code Playgroud)

我知道列表初始化不允许缩小,这样初始化int x{3.5};就不会编译.但除此之外,我还有几个问题:

 
(1)
obj s("value");和之间的编译器输出有什么不同obj s{"value"};吗?
让我们考虑一个没有任何优化的编译器.我想知道任何可能的技术差异:-)

 
(2)也许我应该问一个多变量初始化完全相同的问题,例如:
obj s("val1", "val2");obj s{"val1", "val2"};

 
(3)我注意到列表初始化有时可以调用不同的构造函数,如:

vector<int> a{10,20};   //Curly braces -> fills the vector with the arguments
vector<int> b(10,20);   //Parentesis -> uses arguments to parameterize some functionality
Run Code Online (Sandbox Code Playgroud)

怎么可能?  
 

我们在这里涵盖了所有可能的初始化吗?
根据我对C++的有限知识,我相信所有可能的对象初始化(本机类型或用户定义类型的对象)已在上面的示例中介绍过.那是对的吗?我忽略了什么吗?  
 


PS:我正在学习C++(我知道C,但还不是C++),所以请不要对我太过努力;-)

Whi*_*TiM 7

 
(1)
obj s("value");和之间的编译器输出有什么不同obj s{"value"};吗?
让我们考虑一个没有任何优化的编译器.我想知道任何可能的技术差异:-)

 
(2)也许我应该问一个多变量初始化完全相同的问题,例如:
obj s("val1", "val2");obj s{"val1", "val2"};

 
(3)我注意到列表初始化有时可以调用不同的构造函数,如:

vector<int> a{10,20};   //Curly braces -> fills the vector with the arguments
vector<int> b(10,20);   //Parentesis -> uses arguments to parameterize some functionality
Run Code Online (Sandbox Code Playgroud)

怎么可能?

  • 如果类类型有一个初始化列表构造函数obj,那么在你的情况下,它总是优于其他其他构造函数的brace-init-initializers(列表初始化)obj s{"value"};;

    这意味着如果你有一个构造函数std::initializer_list<T>作为其第一个参数而其他参数是默认的,那么它是首选.例

    struct A{
        A(std::initializer_list<std::string>);    //Always be preferred for A a{"value"}
        A(std::string);
    };
    
    Run Code Online (Sandbox Code Playgroud)

    std::vector<T>和其他STL容器有这样的初始化列表构造函数.

  • 否则,重载决策启动并且它会回退到由重载解析过程选择的任何可用构造函数;

  • 否则,如果类没有用户定义的构造函数并且它是聚合类型,则它会直接初始化类成员.


我们在这里涵盖了所有可能的初始化吗?
根据我对C++的有限知识,我相信所有可能的对象初始化(本机类型或用户定义类型的对象)已在上面的示例中介绍过.那是对的吗?我忽略了什么吗?

不.你没有.排除引用初始化,有五种方法可以在C++中初始化对象.

  • 直接初始化
  • 列表初始化
  • 复制初始化
  • 价值初始化
  • 聚合初始化(仅适用于聚合类型)

您可以在此处找到更多信息

  • 我想补充一点,列表初始化保证了从左到右的参数评估顺序,所以如果你需要从类似流的资源中提取参数,你应该在构造函数括号之外或者使用列表初始化. (2认同)
  • @K.Mulier,*list-initialization* 的概念是在初始化期间使用元素填充容器或对象;如果您查看 [管理其行为的规则](http://eel.is/c++draft/dcl.init.list#3),您会发现它可能会回落(尽管技术上不可接受)到其他初始化方法。因此,如果标准库的 `std::vector` 中没有 *initializer-list 构造函数*,那么 `vector&lt;int&gt; a{10,20};` 和 `vector&lt;int&gt; b(10,20);`实际上是相同的。所以,是的,提供这样的 *initializer-list 构造函数* 会有所不同。 (2认同)

Sem*_*rov 7

列表初始化保证从左到右的参数评估顺序。在本例中,我们std::tuple将从istream数据创建,然后可以在此处找到输出元组示例

#include <iostream>
#include <sstream>
#include <tuple>

template<typename T, typename CharT>
T extract(std::basic_istream<CharT>& is) {
    T val;
    is >> val;
    return val;
}

void print(const std::tuple<int, long, double>& t) {
    using std::cout;
    cout << std::get<0>(t) << " " << std::get<1>(t) << " " << std::get<2>(t) << std::endl;
}

int main()
{
    std::stringstream ss1;
    std::stringstream ss2;
    ss1 << 1 << " " << 2 << " " << 3;
    ss2 << 1 << " " << 2 << " " << 3;
    auto compilerOrder    = std::tuple<int, long, double>( extract<int>(ss1), extract<long>(ss1), extract<double>(ss1) );
    auto leftToRightOrder = std::tuple<int, long, double>{ extract<int>(ss2), extract<long>(ss2), extract<double>(ss2) };
    print(compilerOrder);
    print(leftToRightOrder);
}
Run Code Online (Sandbox Code Playgroud)

输出:

3 2 1
1 2 3
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,当我们在函数括号内多次使用相同的类似流的资源时,就会看到差异。

还有我的问题