c++variadic-templatestype-traits

how to create a template with both default type argument and variadic type argument? or any work around


I created a trait struct FnOnArg to see if Fn can call on Arg

template<typename Fn, typename Arg, typename=void>
struct FnOnArg: std::false_type {};

template<typename Fn, typename Arg>
struct FnOnArg<Fn, Arg, std::void_t<decltype(std::declval<Fn>()(std::declval<Arg>()))>>: std::true_type {};

It can only work on Fn with one argument I want to create FnOnArgs like

template<typename Fn, typename... Args, typename=void>
struct FnOnArgs;

but variadic and default template argument both should be the last argument Any workaround to achieve FnOnArgs?


Solution

  • You move the dummy template argument typename = void to have it somewhere before typename... Args.

    This means it can no longer have the default argument (= void), so you remove it and pass void explicitly.

    You then create another template that wraps this one and adds void automatically, so you don't have to pass it every time.

    template <typename Void, typename Fn, typename ...Args>
    struct FnOnArgsLow : std::false_type {};
    
    template <typename Fn, typename ...Args>
    struct FnOnArgsLow<std::void_t<decltype(std::declval<Fn>()(std::declval<Args>()...))>, Fn, Args...> : std::true_type {};
    
    // The wrapper can be a variable or a class, whatever you like more.
    template <typename Fn, typename ...Args>
    static constexpr bool FnOnArgs = FnOnArgsLow<void, Fn, Args...>::value;