1
#include <iostream>
#include <utility>

template<typename T>
void f1(T&& t) // && 
{

  if constexpr (std::is_function_v<typename std::remove_pointer_t<T>>)
                 std::cout << "function" << std::endl;
  else
    std::cout << "not a function" << std::endl;
}


template<typename T>
void f2(T& t) // & 
{

  if constexpr (std::is_function_v<typename std::remove_pointer_t<T>>)
                 std::cout << "function" << std::endl;
  else
    std::cout << "not a function" << std::endl;
}


void print(){}


int main()
{
    f1(print);
    f2(print);

    return 0;
}

According to f1, print is not a function.

According to f2, print is a function.

Understanding why this is so would help understanding the && operator

Vince
  • 3,979
  • 10
  • 41
  • 69
  • 1
    The `&` and `&&` operators in your function parameters are *not* logical AND - they are, respectively, the reference operator and the [r-value reference operator](https://stackoverflow.com/a/39480244/10871073). – Adrian Mole Feb 23 '20 at 19:45
  • @AdrianMole Here they are not operators at all. – HolyBlackCat Feb 23 '20 at 19:50
  • @HolyBlackCat Fair point. Too late to edit my comment, but I think the link I gave should be the (new) dupe target. – Adrian Mole Feb 23 '20 at 19:52
  • 3
    @Vince Check [this](http://coliru.stacked-crooked.com/a/7008beaceb980674) out. To understand why `T` becomes `void (&)()` in the first case, read about *forwarding references* (`T&&` is one). – HolyBlackCat Feb 23 '20 at 19:54

1 Answers1

1

In the both cases a function is passed by reference. And the both functions deals with lvalue reference to the function print.

Use

std::is_function_v<std::remove_reference_t<T>>

instead of

std::is_function_v<typename std::remove_pointer_t<T>>

You can also insert a statement like this in the both functions

std::cout << std::is_lvalue_reference_v<decltype( t )> << '\n';

to be sure that the functions deal with the lvalue reference to rpint.

Take into account that you need to include the header <type_traits>.

If you want that the functions would deal with function pointers then you need to use a call like this

f1(&print);

In this case the second function should be declared like

template<typename T>
void f2( const T& t);

Otherwise you may not bind a non-constant reference to rvalue.

Or call the function f2 like if you do not want to use the qualifier const.

auto p = print;

f2(p);
Vince
  • 3,979
  • 10
  • 41
  • 69
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335