Разница между типами "веселья" и "веселья"?

Действительно ли выражения 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 не выполняются.

[Акцент мой]