列出C ++中的初始化,Initializer_list和相关问题 [英] List initialization, Initializer_list and related questions in C++

查看:65
本文介绍了列出C ++中的初始化,Initializer_list和相关问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这是在stackoverflow上进行了广泛讨论的主题,但是我很难找到彻底的答案,以消除我在C ++中与列表初始化和initializer_lists有关的所有困惑,因此我将尝试一下并问我自己的问题.

I know it's a subject that has been discussed quite extensively here on stackoverflow but I've a hard time finding thorough answers removing all the confusion I've concerning list initialization and initializer_lists in C++, so I will just give it a try and ask my own questions.

请考虑以下代码段:

class C
{
public :
    C(int a, int b, int c) : _a (a), _b(b), _c(c) {}; //initialization_list with ()
    //C(int a, int b, int c) : _a{ a }, _b{ b }, _c{ c } {}; //initialization list with {}
private :
    int _a, _b, _c;
};

int main()
{
    C a(5.3,3.3,4.3); // no list
    C b{5.3,3.3,4.3}; // list {}
    C c({5.3,3.3,4.3}); // list {}
}

我不明白为什么这两个初始化列表的行为类似?我曾期望,当尝试使用类型_a{a}, _b{b}, _c{c}的初始化列表创建类型为C的对象a时,会得到有关缩小的编译器错误.但是,不会产生任何错误,并且_a, _b and _c仅存储整数值.

I don't understand why those two initialization lists behave similarly? I was expecting, when trying to create the object a of type C using the initialization list of type _a{a}, _b{b}, _c{c} to get a compiler error about narrowing. However, no errors are generated and _a, _b and _c just store the integer values.

仅当使用列表"{}"创建对象b或c时,编译器才会生成缩小错误消息.这是为什么?我不知道的使用{}或()编写初始化列表之间是否有区别,或者行为是否相同?

It's only when creating the objects b or c using a list "{}" that the compiler generates a narrowing error message. Why is that? Is there any differences between writing an initialization list using {} or () that I'm unaware of or are the behaviours identical?

问我下一个问题:

class C
{
public :

//private :
    int _a, _b, _c;
};

int main()
{
    C a(5,3,4); //obviously doesn't work as no such constructor
    C b{5,3,4}; //work only if _a, _b and _c are not private nor protected!
}

第二个语句(带有大括号)仅在变量为公共变量时才起作用吗?涉及的机制是什么?

How comes that the second statement (with braces) only works if the variables are public? What is the mechanism involved?

因此,我想更好地理解,除了创建带有列表{}的对象所提供的缩小安全性" 之外,该列表还具有哪些其他功能" 机制提供?因为在第二个调用中,它仍然是被调用的默认构造函数(因此,不是以initializer_list作为参数的默认构造函数),对吗?

So I would like to better understand, beside the "narrowing safety" provided by creating an object with a list {}, what other "functionalities" does this list mechanism provide ? Because in the second call, it's still the default constructor that is called (hence, not a default constructor taking an initializer_list as argument), right ?

最后,想象一下在我的class C中,我还有另一个构造函数,该构造函数将初始化列表作为参数.

Lastly, imagine in my class C I've another constructor taking an initializer list as parameter.

class C
    {
    public :
        C() = default; //default constructor
        C(int a, int b, int c) : _a (a), _b(b), _c(c) {};
        C(std::initializer_list<int> a) { //do some stuffs with the list};
    private :
        int _a, _b, _c;
    };

很明显,如果试图创建一个使用任意数量的整数但3(或实际上为0)的对象,则将调用采用initializer_list的构造函数.但是,如果创建这样的对象:

It's pretty obvious that, if trying to create an object taking any numbers of integers but 3 (or 0 actually), the constructor taking the initializer_list will be invoked. If creating an object like that however :

C c();

C c{};

将调用默认构造函数.但是,如果使用完全 3 个整数创建对象:

the default constructor will be called. But if creating an object with exactly 3 integers :

C c(5,2,3);

C c{5,2,3};

initializer_list构造函数将被调用.规则是这样的:

the initializer_list constructor will be called. The rule goes like that :

  • 如果可以调用默认构造函数或初始构造器列表构造函数,则首选默认构造函数
  • 如果可以同时调用初始化列表构造函数和普通构造函数",则最好使用初始化列表构造函数
  • If either a default constructor or an initializer-list constructor could be invoked, prefer the default constructor
  • If both an initializer-list contructor and an "ordinary constructor" could be invoked, prefer the initializer-list constructor

因此,(如果我错了,请纠正我),如果我这样创建对象:

Therefore (and correct me if I'm wrong), if I create my object like that :

C c{5,3,4};

将调用iniatializer-list构造函数.但是,如果我这样创建对象:

The iniatializer-list constructor will be called. However, if I create my object like that :

C c(5,3,4);

将调用第二个构造函数(以3个整数作为参数).我的问题是:如果我也想提供缩小的安全性,该如何用第二个构造函数而不是inialtializer-list创建对象? (因为如果我按照该问题的第一个示例中的方法进行操作,则将调用initializer-list构造函数!).

The second constructor (taking 3 ints as arguments) will be called. My question is : how can I create an object with this second constructor instead of the iniatializer-list one if I want to provide narrowing safety as well ? (because if I do as in the first example of this question, the initializer-list constructor will be called instead !).

请毫不犹豫地举例说明您的答复,并讨论与列表相关的概念,我在这个问题中没有提到过.我想很好地掌握这些.谢谢.

Don't hesitate to examplify your replies and to discuss on list-related concepts I haven't talk in this question. I would like to get a very good grasp on those. Thanks.

推荐答案

因此,只要使用花括号,就使用集合初始化,一种对结构或类进行初始化的方法,该方法按顺序或通过指定符进行初始化.例如,

So anytime curly braces are used you are using aggregate initialization, a method of initialization for structs or classes that initializes in order., or via a designator. For example,

#include <iostream>

struct Foo
{
  int a;
  char b;
};

class Doo
{
public: 
  double h;
  char ch;
};

int main() {
  Foo first = {3, 't'};
  std::cout << first.b << "\n";
  //t
  Doo second = {'3', 50};
  std::cout << second.ch << "\n";
  //2 interpreted as char
}

在这里,当我们使用{}初始化类或结构时,它们总是被解释为按照类中列出的顺序.这就是为什么打印"2"的原因,因为ASCII中的50对应于字符"2".

Here, when we use the {} to initialize a class or struct, they are always interpreted as being in the order listed in the class. That's why '2' was printed since 50 in ASCII corresponds to the character '2'.

构造函数初始化

因此,您还可以对构造函数初始化列表使用相同的逻辑,

So you can also use the same logic with constructor initialization lists,

#include <iostream>

struct Pair
{
  int first;
  long second;
};

class Couple
{
public:
  Pair p;
  int g;
public:
 Couple(): p{3, 700}, g{3}
 {}
};

int main() {
  Couple test;
  std::cout << test.p.first << "\n";
  //3
}

在这里,p旁边的{3, 700}与在代码中其他位置使用的Pair p = {3, 700};相同.您基本上使用顺序聚合初始化.现在,如果将配对"字段的花括号更改为括号,会发生什么情况?

Here, the {3, 700} next to p, would be the same as Pair p = {3, 700}; used else where in code. Your basically using an in order aggregate initialization. Now, what happens if we change the curly braces for the Pair field to parenthesis?

我们收到此错误

main.cpp: In constructor 'Couple::Couple()':
main.cpp:15:26: error: no matching function for call to 'Pair::Pair(int, int)'
  Couple(): p(3, 700), g{3}

那是因为我们没有用于Pair的构造函数,该构造函数接受两个数字.因此,聚合初始化和括号之间的主要区别在于,您需要为使用括号创建的任何特定参数集实现构造函数,而对于花括号,您可以仅使用编译器提供给您的默认参数.

That's because we don't have a constructor for Pair that accepts two numbers. So the key difference between the aggregate initialization and the parenthesis is you need to have constructors implemented for any specific set of arguments you make with parenthesis, yet with curly braces you can just use the default one the compiler hands you.

std :: initializer_list是容器的不常用形式,用于带有{}的初始化列表中的多个参数.

The std::initializer_list is a not-commonly used form of container for multiple arguments in initialization lists with {}.

这篇关于列出C ++中的初始化,Initializer_list和相关问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆