I have a templated function where the only template parameter is used for passing a function pointer, and I want to be able to set a default argument (a specific function) to that parameter but it doesn't seem to work as I expected. Setting a default argument to the template parameter does not allow me to call the function with the defaulted argument omitted unless I make a separate overload instead. Is there a way to accomplish this using default arguments?
Here's what I tried at first, validator
being the problematic parameter:
template <typename FuncT>
std::string ask_for(size_t arg_index, const std::string & prompt,
FuncT validator = Validators::is_not_empty, // default does not work!
std::ostream & os = std::cout);
(Validators
is a namespace containing helper functions intended to pass to this function.)
The last parameter os
does react to the default argument as I expected; ask_for(0, Validators::does_file_exist)
works with os
being set to std::cout
.
But if I call ask_for(1)
it does not call ask_for(1, Validators::is_not_empty)
as I expected, instead it gives me this error trace:
error: no matching function for call to 'ask_for(int, const char [64])'
note: candidate: 'template<class FuncT> std::string ask_for(size_t, const std::string&, FuncT, std::ostream&)'
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter 'FuncT'
Shouldn't it be able to deduce the template parameter by the given default argument? Or am I misunderstanding how default arguments are implemented for template parameters?
However, I was able to get the expected behavior by writing a separate overload and calling it instead:
template <typename FuncT>
std::string ask_for(size_t arg_index, const std::string & prompt,
FuncT validator, // no default here...
std::ostream & os = std::cout);
// ...overloaded version calls function with desired default argument
std::string ask_for(size_t arg_index, const std::string & prompt)
{
return ask_for(arg_index, prompt, Validators::is_not_empty);
}
Is there a way to set a default argument for the templated parameter to a function pointer, or must I create a separate overload to achieve this? Would this be possible with a template specialization or if I remove the template parameter altogether and use a specific function pointer instead?
I would like the default argument notation for readability, but I am mostly interested in efficiency.
CodePudding user response:
Default argument cannot be used to deduce a template argument, but you can also default FuncT
.
template <typename FuncT = decltype(&Validators::is_not_empty)>
std::string ask_for(size_t arg_index,
const std::string & prompt,
FuncT validator = &Validators::is_not_empty,
std::ostream & os = std::cout);