Как передаётся brace-init-list в std::vector::push_back?

У меня есть std::vector<std::string>. Если я в него делаю push_back({ '1', '2' }), то всё ок. Но если сделать в него emplace_back(std::move({ '1', '2' })), то код не скомпилируется, хотя, судя по реализации push_back, он делает буквально то же самое.

_CONSTEXPR20 void push_back(_Ty&& _Val) {
    // insert by moving into element at end, provide strong guarantee
    emplace_back(_STD move(_Val));
}

Каких нюансов я не понимаю? И каким образом brace-init-list доходит до конструктора строки в векторе при использовании push_back? Ведь brace-init-list не является объектом, как на него можно rvalue reference делать?


Ответы (1 шт):

Автор решения: HolyBlackCat

Чтобы std::move({'1', '2'}) сработал, компилятору нужно угадать шаблонный параметр move (тип параметра функции) из типа {'1', '2'}. А у фигурных скобок нет типа1 - поэтому здесь ошибка.

Зато в push_back(_Ty &&) тип параметра известен заранее (из шаблонного параметра вектора), поэтому при вызове из фигурных скобок создается временный объект этого типа.

brace-init-list не является объектом, как на него можно rvalue reference делать?

Ссылка не на него, а на временный объект, который из него создается.


1 Нет, тип не std::initializer_list<char>. Это заметнее на вот таком примере:

struct A {int x; std::string y;};
std::vector<A> a;
a.push_back({1, "2"}); // Явно не `initializer_list<??>`.
→ Ссылка