Разница между типами "веселья" и "веселья"?
Действительно ли выражения fun
и &fun
имеют один и тот же тип или нет?
Рассмотрим следующий код:
template <typename Check, typename T>
void check(T)
{
static_assert(is_same<Check, T>::value);
}
void fun()
{}
check<void(*)()>(fun);
check<void(*)()>(&fun);
cout << typeid(fun).name() << endl;
cout << typeid(&fun).name() << endl;
Оба утверждения преуспевают, что предполагает, что оба выражения имеют один и тот же тип. Однако typeid
возвращает разные результаты:
FvvE
PFvvE
Это почему?
Ответы
Ответ 1
Оба утверждения преуспевают, потому что они применяются к типу T
выведенному из аргумента функции. В обоих случаях он будет выводиться как указатель на функцию, потому что функции распадаются на указатель на функцию. Однако, если вы переписываете утверждения для непосредственного приема типов, то сначала один не будет работать:
static_assert(is_same<void(*)(), decltype(fun)>::value);
static_assert(is_same<void(*)(), decltype(&fun)>::value);
онлайн-компилятор
Ответ 2
fun
и &fun
ссылаются на один и тот же тип из-за функции преобразования указателя, которая выполняется в check<void(*)()>(fun);
; но typeid
является исключением.
(акцент мой)
Преобразования Lvalue-to-rvalue, array-to-pointer или function-to-pointer не выполняются.
И почему функция преобразования указателя выполняется для check<void(*)()>(fun);
, потому что в выводе аргумента шаблона,
Перед началом дедукции выполняются следующие корректировки для P и A:
1) Если P не является ссылочным типом,
- если A - тип массива,...;
- в противном случае, если A - тип функции, A заменяется типом указателя, полученным из преобразования функции в указатель;
check()
принимает параметр по значению, затем выполняется преобразование "функция-к-указателю", и вычисленный тип T
будет также указателем функции, т.е. void(*)()
.
Ответ 3
Когда вы используете имя функции в качестве выражения, оно распадается на указатель на себя. Так fun
будет так же, как &fun
.
Что касается typeid
вещи, из этой справки:
Преобразования Lvalue-to-rvalue, array-to-pointer или function-to-pointer не выполняются.
[Акцент мой]