Search code examples
c++decltypeis-same

function type when used with decltype


I was looking into decltype and std::is_same_v and tried them on functions.

template<typename T>
void func(T t){}

template<typename T>
using f = decltype(func<T>);

template<typename T>
using ff = decltype((func<T>));

template<typename T>
using fff = void(*)(T);


template<typename T, typename U, typename Z>
void test(T t, U u, Z z){
   std::cout << __PRETTY_FUNCTION__ << std::endl;
   std::cout << std::boolalpha
             << std::is_same_v<T, U> << " "
             << std::is_same_v<U, Z> << " "
             << std::is_same_v<Z, T>;
}
int main()
{
    f<int> f1; // 1
    ff<int> ff1 = func<int>; // 2
    fff<int> fff1 = func<int>;

    test(f1, ff1, fff1);
    return 0;
}

link to the demo

Output:

void test(T, U, Z) [with T = void (*)(int); U = void (*)(int); Z = void (*)(int)]
true true true

While editing I removed parameter by mistake and ran the code. link to the demo

template<typename T, typename U, typename Z>
void test(T t, U u) // Z z is missing
{ // nothing changed in the body }
no matching function for call to 'test(void (&)(int), void (&)(int), void (*&)(int))'
   36 |     test(f1, ff1, fff1);
      |                       ^

It looks like Z is different type but std::is_same_v<U, Z> gives true. And I thought ff and f would be different types as per decltype in cpprefernce

Note that if the name of an object is parenthesized, it is treated as an ordinary lvalue expression, thus decltype(x) and decltype((x)) are often different types.


  1. When I try to initialize f f1 = func<int>; I get a warning and an error.
 warning: declaration of 'void f1(int)' has 'extern' and is initialized
   32 |     f<int> f1 =func<int>;
      |            ^~
<source>:32:16: error: function 'void f1(int)' is initialized like a variable
   32 |     f<int> f1 =func<int>;
      |                ^~~~~~~~~
  1. When I don't initialize ff ff1; I get an error saying
error: 'ff1' declared as reference but not initialized
   33 |     ff<int> ff1 ;
      |             ^~~

As far as I know, I got reference type due to decltype((func<T>)) but std::is_same_v gave true in test.

Apparenlty, std::is_same_v tells all three are same yet they are different. I'm a beginner in c++ and I'm not able to comprehend what's going.


Solution

  • Your code is similar to:

    f<int> f1;                 // `void f1(int);`, function declaration
    ff<int> ff1 = func<int>;   // `void (&ff1)(int) = func<int>;`, reference to function
    fff<int> fff1 = func<int>; // `void (*fff1)(int) = &func<int>;` pointer to function,
                               // decay of `func<int>` to pointer
    

    As C-array, you cannot pass function by value; they decay to pointer.

    so

    test(f1, ff1, fff1); // test(&f1, &ff1, fff1);
    

    and inside test, all parameter have void (*)(int) type.