Каков возвращаемый тип инициализации списка?

Кто-нибудь хотел бы объяснить, почему дела 1 и 2 имеют разные выходные данные для этого фрагмента кода.

struct A {
    A() { cout << "A()" << endl; }
    A(int i) { cout << "A(int)" << endl; }
    A(const A&) { cout << "A(const A&)" << endl; }
    A(A&&) noexcept { cout << "A(A&&)" << endl; }
    A& operator=(const A&) { cout << "operator=(const A&)" << endl; return *this; }
    A& operator=(A&&) noexcept { cout << "operator=(A&&)" << endl; return *this; }
    friend bool operator< (const A&, const A&) { return true; }
};

int main() {
    std::set<A> aSet;
    aSet.insert(1);       // case 1
    //aSet.insert({1});   // case 2

    return 0;
}

Для случая 1 вывод:

A(int)
A(A&&)

а для случая 2 это:

A(int)
A(const A&)

Версия компилятора:

g ++ - версия g++-7 (SUSE Linux) 7.2.1 20170901 [редакция gcc-7-branch 251580] Copyright (C) 2017 Free Software Foundation, Inc.

1 ответ

Решение

Соответствующие перегрузки std::set::insert являются:

std::pair<iterator,bool> insert( value_type const& value ); // #1
std::pair<iterator,bool> insert( value_type&& value );      // #2
void insert( std::initializer_list<value_type> ilist );     // #6

Когда вы звоните aSet.insert(1); который вызывает № 2 предпочтительнее № 1 - который собирается создать новый A с помощью A(int ) а затем переместить его в набор. Следовательно, A(A&& ),

Тем не менее, когда вы звоните aSet.insert({1}) выбранная перегрузка #6. Всякий раз, когда вы используете инициализацию списка, std::initializer_list Кандидат является наиболее предпочтительным (в основном, мы разрешаем перегрузку сначала только с учетом этих кандидатов, а затем, только если мы не найдем ее, мы переделываем разрешение перегрузки с учетом остальных). поскольку std::initializer_list поддерживается const массив, как только мы создадим A с помощью A(int ) мы должны скопировать это - мы не можем переместить это. следовательно A(A const& ),

Другие вопросы по тегам