Search code examples
c++templatesc++17conditional-typesclass-template

std::conditional - Invalid parameter type ‘void’ even when testing for 'void'


The following compiles on Visual Studio:

template<typename ArgType, typename ReturnType>
struct Test
{
    using FunctionPointerType = std::conditional_t<
        std::is_same_v<ArgType, void>
        , ReturnType(*)()
        , ReturnType(*)(ArgType)
    >;
    FunctionPointerType Func;
};

int main()
{
    Test<void, char> tt;
}

But does not compile on Linux g++. The error I get is

error : invalid parameter type ‘void’

I know I cannot use void in templates, which is why I have used std::conditional_t and std::is_same_v.

I cannot see what is incorrect, can someone please tell me?


Solution

  • In std::conditional_t<B, T, F> both the true and false specialization should have valid types T as well as F. In your case, since the F deduce to an invalid char(*)(void) type, std::conditional can not be used here.

    I would suggest a helper traits function_ptr_t as alternative

    #include <type_traits>
    
    template<typename RetType, typename... Args> struct function_ptr final {
        using type = RetType(*)(Args...);
    };
    
    template <typename RetType> struct function_ptr<RetType, void> final {
        using type = RetType(*)();
    };
    // alias helper
    template<typename RetType, typename... Args>
    using function_ptr_t = typename function_ptr<RetType, Args...>::type;
    
    
    template<typename RetType, typename... Args>
    struct Test
    {
         function_ptr_t<RetType, Args...> Func;
    };
    

    See a demo


    Note that, I have swapped the template arguments in the class template Test, and made the second template argument be a variadic, so that the Test<char> will result in a member function pointer of type char(*)().

    That means the following will work:

    Test<char> tt1;
    static_assert(std::is_same_v<char(*)(), decltype(tt1.Func)>, " are not same!");
    
    Test<char, void> tt2;
    static_assert(std::is_same_v<char(*)(), decltype(tt2.Func)>, " are not same!");
    
    Test<void, double> tt3;
    static_assert(std::is_same_v<void(*)(double), decltype(tt3.Func)>, " are not same!");
    

    If that is not, you wanted, substitute the variadic template arguments to be a normal one.