32

Do expressions fun and &fun have the same type or not?

Consider the following code:

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;

Both assertions succeed which suggests that both expressions have the same type. However, typeids return different results:

FvvE
PFvvE

Why is that?

3 Answers 3

30

Both assertions succeed because they are applied to the type T deduced from function argument. In both cases it will be deduced as a pointer to function because functions decay to a pointer to function. However if you rewrite assertions to accept types directly then first one will fail:

static_assert(is_same<void(*)(), decltype(fun)>::value);
static_assert(is_same<void(*)(), decltype(&fun)>::value);

online compiler

18

fun and &fun refer to the same type because of function to pointer conversion, which is performed in check<void(*)()>(fun);; but typeid is an exception.

(emphasis mine)

Lvalue-to-rvalue, array-to-pointer, or function-to-pointer conversions are not performed.

And why the function to pointer conversion is performed for check<void(*)()>(fun);, because in template argument deduction,

Before deduction begins, the following adjustments to P and A are made:

1) If P is not a reference type,

  • if A is an array type, ...;
  • otherwise, if A is a function type, A is replaced by the pointer type obtained from function-to-pointer conversion;

check() takes parameter by value, then function-to-pointer conversion is performed and the deduced type of T will be the function pointer too, i.e. void(*)().

0
7

When you use a function name as an expression, it decays to a pointer to itself. So fun will be the same as &fun.

As for the typeid thing, from this reference:

Lvalue-to-rvalue, array-to-pointer, or function-to-pointer conversions are not performed.

[Emphasis mine]

5
  • Why do typeids return different type names?
    – NPS
    Commented Jan 23, 2018 at 10:09
  • @NPS Because function-to-pointer conversions are not performed.
    – Zereges
    Commented Jan 23, 2018 at 10:16
  • [conv.func]/1 says it can ("An lvalue of function type T can be converted to a prvalue of type “pointer to T ”. The result is a pointer to the function."), but I cannot find a rule saying it does.
    – YSC
    Commented Jan 23, 2018 at 10:19
  • @YSC It does in template argument deduction; check takes argument by value and the deduced type T will be the function pointer. Commented Jan 23, 2018 at 10:32
  • What does it mean "use as an expression"? When is that? When is it not?
    – NPS
    Commented Jan 23, 2018 at 15:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.