4

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.

TheScore
  • 329
  • 3
  • 14
  • 2
    Not a full answer, so posting as a comment. The diagnostic you got shows mismatching types [before the values decayed](https://en.cppreference.com/w/cpp/types/decay). Notice how [these decayed types](https://godbolt.org/z/n8erneoPq) match the output of those in your first example that compiles. – Patrick Roberts Apr 24 '21 at 08:29
  • @PatrickRoberts Thank you. From question `ff` is a refernce type function pointer, `f` is a function pointer(not sure). Is it that always there are decayed just like arrays are decayed to pointer when passed to a function? – TheScore Apr 24 '21 at 08:36
  • 2
    [Neither `ff` nor `f` are initially pointer types (though `fff` is)](https://godbolt.org/z/E58x7E5o7), `f` is a value type and `ff` is a reference type, but both decay to pointers when passed to `test()`. – Patrick Roberts Apr 24 '21 at 08:42
  • @PatrickRoberts Thank you so much. Now it makes a lot more sense. I should have put `std::is_same_v` in the main itself. `std::is_same_v>` -> `true`...`std::is_same_v>` -> `true`...`std::is_same_v>` -> `true`. I hope I got all the types correct. Please consider adding an answer. I'll accept it. Again thank you for your time and patience. – TheScore Apr 24 '21 at 10:13
  • I don't understand the error given by `f f1 = func;` what does it mean tho? – TheScore Apr 24 '21 at 10:15

1 Answers1

2

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.

Jarod42
  • 203,559
  • 14
  • 181
  • 302