c++c++11templatesstandardstype-traits

Why does `std::is_function_v` not work as expected?


#include <iostream>
#include <type_traits>
#include <iomanip>

using namespace std;

template<typename T>
bool f(T&& v)
{
    return is_function_v<decltype(forward<T>(v))>;
}

int main()
{
    cout << boolalpha
        << is_function_v<decltype(setw)>
        << endl;

    cout << boolalpha
        << f(setw)
        << endl;

    return 0;
}

The outout is: (clang 6.0 & gcc 8.0)

>

true

false

But the result I expect should be:

>

true

true

Why does std::is_function_v not work as expected?


Solution

  • You need to remove reference on T.

    template<typename T>
    bool f(T&& v)
    {
        return is_function_v<remove_reference_t<decltype(forward<T>(v))>>;
        //                   ~~~~~~~~~~~~~~~~~~
    }
    

    When pass setw to f, it's an lvalue, then the forwarding reference type T will be deduced as an lvalue reference to function. For std::is_function, references to function (and pointers to function etc) don't count as function types.


    BTW: the forwarding reference type T will be deduced as either lvalue reference or rvalue reference; and using decltype on std::forward would always yield a reference type, either lvalue reference or rvalue reference.