c ++: вызов конструкторов с помощью фигурных скобок? - PullRequest
4 голосов
/ 12 февраля 2020
class A 
{
    int value_;
    public:
    A(int value):value_(value){}
};

A get_a1(int value)
{
    return A(value);
}

A get_a2(int value)
{
    return {value};
}


int main()
{
    A a1 = get_a1(1);
    A a2 = get_a2(2);
}

В чем разница между get_a1() и get_a2(), если есть?

Как называется return {value};? (Я полагаю, «вызов конструкторов через фигурные скобки» не является правильным способом ссылки на это)

1 Ответ

4 голосов
/ 12 февраля 2020

В вашем случае просто нет разницы. Но если вы немного измените свой код, будет заметна разница!

Прежде всего, вы можете создать свой тип по-разному, все описано здесь: инициализация

Разница возникает, если ваш класс также предоставляет конструктор, который принимает std::initializer_list.

См. Следующий код, измененный / расширенный, чтобы показать разницу:

class A 
{   
    public:
        A(int value):value_(value){ std::cout << "int" << std::endl;}
        A(const std::initializer_list<int>& ){ std::cout << "list" << std::endl;}
        void print()
        {   
            std::cout << value_ << std::endl;
        }   
    private:
        int value_;
};  

A get_a1(int value)
{   
    std::cout << "()" << std::endl;
    return A(value);
}   

A get_a2(int value)
{
    std::cout << "{}" << std::endl;
    return {value};
}


int main()
{   
    A a1 = get_a1(1);
    a1.print();
    A a2 = get_a2(2);
    a2.print();
}   

Если вы запустив эту прогу, вы увидите, что использование {} вызовет конструктор с std::initializer_list, а использование () - ваш конструктор int.

Почему это описано здесь в стандарте:

§13.3.1.7 [over.match.list] / p1:

Когда объекты неагрегированного типа класса T инициализируются списком (8.5.4), выбирается разрешение перегрузки конструктор в два этапа:

  • Первоначально функции-кандидаты являются конструкторами списка инициализаторов (8.5.4) класса T, а список аргументов состоит из списка инициализаторов как единственного аргумента. .
  • Если нет viabl Обнаружен конструктор списка инициализатора, снова выполняется разрешение перегрузки, где все функции-кандидаты являются конструкторами класса T, а список аргументов состоит из элементов списка инициализатора.

Если список инициализаторов не имеет элементов, а T имеет конструктор по умолчанию, первая фаза опускается. В случае инициализации copy-list, если выбран конструктор explicit, инициализация некорректна.

Кроме того, конструкторы списка инициализаторов не допускают сужения!

§8.5.4 Инициализация списка

(3.4) В противном случае, если T является типом класса, рассматриваются конструкторы. Применимые конструкторы перечисляются, и лучший выбирается через разрешение перегрузки ([over.match], [over.match.list]). Если для преобразования какого-либо из аргументов требуется сужающее преобразование (см. Ниже), программа некорректна.

...