Все стандартные ссылки ниже относятся к N4659: рабочий черновик, выпущенный после Kona за март 2017 г. / DIS C ++ 17 .
TL; DR: вывод типа возвращаемого значения заполнителя
Не имеет значения, что класс является анонимным, поскольку тип возвращаемого значения выводится исключительно из оператора return
.
// Denote the type of the anonymous class as 'T'.
// Return type deduced to 'T'
auto operator[](const char*)
{
return *this;
}
// Return type deduced to 'T&'
auto& operator[](const char*)
{
return *this;
}
// Return type deduced to 'T&'
decltype(auto) operator[](const char*)
{
return *this;
}
Подробности и соответствующие стандартные отрывки следуют ниже.
Вывод типа возвращаемого заполнителя: auto
(C ++ 11 и новее)
From [expr.unary.op] / 1 [extract, выделение mine]:
[expr.unary.op] / 1 Унарный оператор *
выполняет косвенное обращение : выражение, к которому он применяется должен быть указателем на тип объекта или указателем на тип функции , и результатом будет lvalue, относящееся к объекту или функции, на которую указывает выражение. [...]
Таким образом, результатом *this
является lvalue, относящееся к объекту, для которого вызывается вызов оператора.
From [dcl. spe c .auto] / 1 и [dcl.spe c .auto] / 2 [извлечение, акцент mine]:
[dcl.spe c .auto] / 1 Спецификаторы типа auto
и decltype(auto)
используются для обозначения типа заполнителя, который будет будет заменен позже вычетом из инициализатора. [...]
[dcl.spe c .auto] / 2 Тип заполнителя может отображаться с помощью декларатора функции [...] в любом контексте, в котором такой декларатор действителен. [...] Если объявленный тип возвращаемого значения функции содержит тип заполнителя, тип возвращаемого значения функции выводится из неотброшенных return
операторов [...].
Из [dcl.type.auto.deduct] / 2 и [dcl.type.auto.deduct] / 4 [извлечение, выделение mine]:
[dcl.type.auto.deduct] / 2 Тип T
, содержащий тип заполнителя, и соответствующий инициализатор e
, определяются следующим образом:
- (2.1) для неотброшенного оператора
return
, который встречается в функции, объявленной с типом возврата, который содержит тип заполнителя, T
- объявленный тип возвращаемого значения и e
- это операнд оператора возврата. Если оператор return не имеет операнда, то e
равно void()
; - [...]
[dcl.spe c .auto] / 4 Если заполнитель является автоматическим определителем типа, выводимый тип T'
, заменяющий T
, определяется с использованием правил для вывода аргументов шаблона. [...]
[Пример:
const auto &i = expr;
Тип i
- это выведенный тип параметра u
в вызове f(expr)
следующего шаблона придуманной функции:
template <class U> void f(const U& u);
- конечный пример]
Таким образом, тип возвращаемого значения функции оператора-члена
auto operator[](const char*)
{
return *this;
}
анонимного типа, скажем, T
, является выведенным типом параметр u
в вызове f(*this)
следующего шаблона придуманной функции:
template <class U> void f(U u);
где, как указано выше, *this
- это lvalue, и возвращаемый тип, таким образом, выводится как T
; а именно тип анонимного класса.
Используя тот же аргумент, возврат функции оператора-члена
auto& operator[](const char*)
{
return *this;
}
анонимного типа, скажем, T
, равен T&
.
Согласно приведенному выше аргументу не имеет значения, что класс является анонимным, поскольку тип возвращаемого значения выводится исключительно из оператора return
.
Выведение типа возвращаемого заполнителя: decltype(auto)
(C ++ 14 и новее)
Если бы мы заменили возвращаемый тип заполнителя auto
типом заполнителя decltype(auto)
, то как Тип возвращаемого значения определен.
decltype(auto) operator[](const char*)
{
return *this;
}
From [dcl.type.auto.deduct] / 5 [извлечение, акцент mine]:
Если заполнителем является спецификатор типа decltype(auto)
, T
должен быть только заполнителем. Тип, выведенный для T
, определяется, как описано в [dcl.type. simple], , как если бы e
был операндом decltype
.
И из [dcl.type.simple] / 4 , [dcl.type.simple] /4.3 применяется [extract]:
Для выражения e
тип, обозначенный decltype(e)
, определяется следующим образом:
- [...]
- (4.4) в противном случае, если
e
- lvalue, decltype(e)
- T&
, где T
- тип e
;
как, как указано выше, e
(оператор возврата; *this
) является lvalue, а [dcl.type.simple] /4.1, [dcl.type.simple] /4.2 и здесь не применяется [dcl.type.simple] /4.3.
Таким образом, тип возвращаемого значения в Пример OP, измененный с использованием типа заполнителя decltype(auto)
: T&
.