Home > Software design >  How to set a default argument for a templated function parameter to a function pointer?
How to set a default argument for a templated function parameter to a function pointer?

Time:12-25

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);
  • Related