Зачем использовать std:: initializer_list по ссылке rvalue или по значению?

Большая часть кода С++ 11, который принимает std::initializer_list, я видел, берет его по значению, но иногда он берется ссылкой rvalue. Есть ли веские основания для этого?

Например, почти каждый пример, который я встретил, делает следующее:

class A {
  public:
  A(std::initializer_list<int>);
};

Но я все время вижу, как это происходит:

class B {
  public:
  B(std::initializer_list<int> &&);
};

Я понимаю использование и назначение ссылок rvalue в целом, но почему один из них предпочтительнее другого в случае std::initializer_list? Единственное, о чем я мог думать, это то, что class A позволяет создавать список инициализаторов отдельно, а class B предотвращает это.

std::initializer_list<int> values {1,2,3,4};
A a(values); // valid
B b(values); // error

Но я не могу думать о хорошей причине, почему предотвращение этого было бы желательным достижением.

Итак, зачем брать std::initializer_list по ссылке rvalue вместо значения?

Ответы

Ответ 1

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

Ответ 2

std::initializer_list воплощает ссылочную семантику даже при передаче по значению, поэтому передача по ссылке в лучшем случае вводит в заблуждение. (Он содержит только указатели, не связанные с владельцем.)

Существуют универсальные ссылки, которые привязаны ко всему, но они не могут быть инициализированы синтаксисом braced-init-list (т.е. { x, y }), поэтому получение ссылки initializer_list таким образом приведет к сочетанию обстоятельств.