Search code examples
c++c++11templatestraitsdecltype

template and decltype for void f(int)


I am learning writing my own traits using C++11 borrowing only std::true_type and std::false_type.

I've created the following trait:

#include <iostream>

template <typename F>
struct is_farg1: std::false_type {};

template <typename R, typename A>
struct is_farg1<R (*)(A)> : std::true_type {};

Now consider a program including the above trait, and the following code:

void f(int) {}

int main() {
    std::cout << "is_farg1<decltype(f)>  : " << is_farg1<decltype(f)>::value << std::endl;
    std::cout << "is_farg1<void(*)(int)> : " << is_farg1<void(*)(int)>::value << std::endl;

    return 0;
}

It produces the following output:

is_farg1<decltype(f)>  : 0
is_farg1<void(*)(int)> : 1

My questions:

  1. Why is_farg1<void(*)(int)>::value is true while is_farg1<decltype(f)>::value returned false?
  2. If my trait is incorrectly written then how can I check if the given function has one and only one argument so I could use also decltype(f)?

Solution

  • Becasue decltype(f) gives the exact function type (i.e. void(int)) but not the function pointer type (i.e. void(*)(int)). When decltype is used for entity,

    If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then decltype yields the type of the entity named by this expression.

    You can add another specialization for the function type like

    template <typename R, typename A>
    struct is_farg1<R (A)> : std::true_type {};
    

    LIVE

    Or check the type as function pointer like

    is_farg1<decltype(f)*>::value
    //                  ^
    
    // or
    is_farg1<decltype(&f)>::value
    //                ^
    

    LIVE