Я читаю Эффективный современный C ++ от Скотта Мейерса. Элемент 1 содержит следующий пример:
template<typename T>
void f(T& param); // param is a reference
int x = 27; // x is an int
const int cx = x; // cx is a const int
f(cx); // T is const int,
// param's type is const int&
В пункте 3 появляется следующий пример:
Widget w;
const Widget& cw = w;
auto myWidget1 = cw; // auto type deduction:
// myWidget1's type is Widget
На основании пункта 1 я ожидал myWidget1
тип быть const Widget
, Я что-то пропустил?
В большинстве случаев auto
следует правилам вывода аргументов шаблона:
§ 7.1.6.4 [dcl.spec.auto] / p6:
После того, как тип описатель-идентификатор был определен согласно 8.3, тип объявленной переменной
с использованием описатель-идентификатор определяется по типу его инициализатора с использованием правил для аргумента шаблона
вычет. ПозволятьT
быть типом, который был определен для идентификатора переменнойd
, получатьP
отT
от
заменяя вхожденияauto
либо с новым параметром шаблона изобретенного типаU
или, если инициализатор
это приготовился-INIT-лист (8.5.4), сstd::initializer_list<U>
, Тип, выведенный для переменнойd
затем выводитсяA
определяется с использованием правил вывода аргументов шаблона из вызова функции (14.8.2.1).
§ 14.8.2.1 [temp.deduct.call] / p2:
Если
P
не является ссылочным типом:
- […]
Если
A
это cv-квалифицированный тип, cv-квалификаторы верхнего уровняA
тип игнорируются для вывода типа.
Если ты хочешь myWidget1
быть типом const Widget&
, он должен быть объявлен как ссылочный тип, например:
auto& myWidget1 = cw;
// ^
auto myWidget1 = cw;
следует третьему правилу вывода типа аргумента шаблона в книге Мейерса, который передается по значению.
Когда вы передаете по значению, cv-qualifiers и ссылки игнорируются, потому что вы получаете новую копию объекта, поэтому вам не важно, был ли старый объект, с которого вы скопировали, константой или ссылкой.