Search code examples
c++templatesc++20function-templatesclass-template

How to deduce template argument from a function type?


I have a class template which has two parameters.

template <typename Func, typename T>
struct action_ final : public parser_base<action_<Func, T>, T>

The first one is a function type, and the second one is a char like type such as char.

I have this code which builds OK

auto p1 = action_<myTestAction*, char>(testAction);

Here, I have to specify the two template arguments, while if I wrote below:

auto p2 = action_(testAction);

I get a build error that the class template argument deduction failed.


Here is the full test code below which need C++20, where the testAction is a function.

#include <span>
#include <string_view>
#include <vector>

struct Token {};
template <typename T>  struct Viewer;

// explicit specialization for T = Token
template <>  struct Viewer<Token> {
    using type = std::span<Token>; // std::span or derived class
};
// explicit specialization for T = char
template <> struct Viewer<char> {
    using type = std::string_view;
};

// alias template
template <typename T> using ViewerT = typename Viewer<T>::type;

template <typename Base, typename T> struct parser_base {
    using v = ViewerT<T>;
    using charType = T;
};

template <typename Func, typename T>
struct action_ final : public parser_base<action_<Func, T>, T> 
{
    constexpr explicit action_(Func&& func) noexcept
        : func(std::forward<Func>(func))
    {}

    template<typename V, typename Skipper>
    constexpr inline bool visit(V& sv, Skipper& skipper) const& noexcept {
        return func(sv); // func returns false to fail the parse
    }

private:
    Func func;
};

using myTestAction = bool(std::string_view& sv);
constexpr bool testAction(std::string_view& sv) {  return true;  }

int main()
{
    auto p1 = action_<myTestAction*, char>(testAction);

    // build error: class template argument deduction failed
    // auto p2 = action_(testAction); 
    return 0;
}

Any ideas?


EDIT1:

JeJo's answer suggest that I need to use the deduction guide, but I'm still not sure whether the deduction guide can support several function types.

I mean in my test code, the function type is bool(std::string_view& sv), in this case, the T is actually char, but in other cases, the function type could be bool(std::span<Token>), where the T is actually Token type.

My initial guess is that the second template argument T is depend on the first template argument function type.


Solution

  • How to deduce a template argument from a function type?

    You can always provide a deduction guide for your class template

    template <typename Func, typename T = char>
    action_(Func) ->action_<Func, T>;
    

    That been said, you can generalize the deduction guide for any function pointer type, where the argument type of it can be extracted by a type trait, and we make it as default template argument for the deduction guide.

    // traits for finding the arg type!
    template <typename T> struct function;
    template <typename ReType, typename Arg> struct function<ReType(*)(Arg)> {
        using arg_type = Arg;
    };
    
    // type alias for convenience.
    template <typename FunctionPtr> 
    using function_arg_t = typename function<FunctionPtr>::arg_type;
    
    //....
    
    // deduction guide
    template <typename Func, typename T = function_arg_t<Func>>
    action_(Func) -> action_<Func, T>;
    

    See a live demo in godbolt.com


    I have this code which builds OK`

    auto p1 = action_<myTestAction*, char>(testAction);

    This is because, you are telling the compiler explicitly, what are the template parameters type to deduce.