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.
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.