Странное поведение конструктора - PullRequest
0 голосов
/ 01 ноября 2018

Я использую Visual Studio 2013, и вот что я пытаюсь выяснить:

#include <iostream>
#include <vector>
using namespace std;

class A
{
public:
    int x = 1;
    bool y = true;

    A(int _x, bool _y) : x(_x), y(_y)
    {
        cout << "Constructor #1" << endl;
    }

    A(std::initializer_list<int> init_list)
    {
        cout << "Constructor #2" << endl;
    }
};


int main(int argc, char** argv)
{
    A Aobj1(10, false);
    A Aobj2(20, "false");
    A Aobj3{30, false};
    A Aobj4{40, "false"};

    return 0;
}

Вывод:

Constructor #1
Constructor #1
Constructor #2
Constructor #1
  • Первый вызов конструктора # 1 в порядке

  • Теперь вторая конструкция Aobj2(int, string), вызывающая конструктор # 1, странная. Как компилятор вызывает конструктор (int, bool) со строковым аргументом? «Ложь» bool даже не преобразуется в int.

  • Aobj3 также в порядке. Хотя initializer_list имеет тип int, компилятор вызывает его из-за инициализации фигурной скобки и преобразует bool в int.

  • Этот снова сбивает меня с толку. Я ожидал, что это будет ошибкой, потому что строка не может быть преобразована в int (как это было с bool), а также ожидал, что компилятор вызовет конструктор initializer_list, потому что это инициализированная скобка. Но компилятор выбирает конструктор (int, bool).

Какое отношение к логике компилятора?

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Теперь вторая конструкция Aobj2(int, string), вызывающая конструктор # 1, странная. Как компилятор вызывает конструктор (int, bool) со строковым аргументом?

Точнее, "false" имеет тип const char[6] и может распадаться до const char*, то есть указатель, а затем может неявно преобразовывать в bool.

Значение типа целочисленного типа с перечислением с плавающей запятой, с незаданной областью, указателя и указателя на элемент может быть преобразовано в значение типа bool.

Нулевое значение (для целочисленного значения, перечисления с плавающей точкой и перечисления с незаданной областью), а также нулевой указатель и значения нулевого указателя на член становятся false. Все остальные значения становятся true.

Для четвертого случая параметр std::initializer_list<int> не может соответствовать аргументу 40, "false", потому что нет неявного преобразования, преобразующего указатель в int. Затем выбирается конструктор, принимающий int, bool, потому что "false" может быть неявно преобразован в bool, как объяснено выше.

0 голосов
/ 01 ноября 2018

"false" - это const char[6], которое уменьшается до const char*, а указатели неявно преобразуются в bool. Вот почему компилятор может вызвать ваш конструктор, взяв int и bool, поскольку компилятору разрешено выполнять неявное преобразование one , чтобы сопоставить аргумент функции.

...