I have a runtime boolean verbose
that if false
excludes some prints to stdout.
To fix ideas, consider to have a lot of parts like:
void add(const int a, const int b, const bool verbose)
{
//...
if(verbose) std::print("{}+{}={}\n", a, b, a+b);
}
My goal is to have something like:
template<typename F>
void add(const int a, const int b, F print_if_verbose)
{
//...
print_if_verbose("{}+{}={}\n", a, b, a+b);
}
The motivation is to simplify the code and make it less error prone (forgetting to test verbose
each print), but also to avoid the various subsystems to be aware of the verbose
parameter.
My first attempts are (godbolt):
template<typename F>
void add(const int a, const int b, F print_if_verbose)
{
print_if_verbose("{}+{}={}\n", a, b, a+b);
}
int main(const int, const char* const argv[])
{
const bool verbose = get_verbose_arg(); // runtime boolean
// This doesn't compile, types are different
//const auto vprint = verbose ? [](const std::string_view msg, const auto&... args){std::vprint_unicode(msg, std::make_format_args(args...));}
// : [](const std::string_view, const auto&...){};
//add(1, 2, vprint);
// This works, but ugly
const auto verb_print = [](const std::string_view msg, const auto&... args){ std::vprint_unicode(msg, std::make_format_args(args...)); };
const auto no_print = [](const std::string_view, const auto&...){};
if(verbose) add(2, 3, verb_print);
else add(2, 3, no_print);
// This works, but tests 'verb' each call
const auto maybe_print = [verb=verbose](const std::string_view msg, const auto&... args){ if(verb) std::vprint_unicode(msg, std::make_format_args(args...)); };
add(3, 4, maybe_print);
}
Is there a way that I'm missing to obtain this assigning the functor once without testing verbose
each time?
You can make the verb_print
/no_print
pair easier to use with a function like this:
constexpr decltype(auto) constexpr_promote(bool x, auto&& f) {
if (x) {
return std::forward<decltype(f)>(f).template operator()<true>();
} else {
return std::forward<decltype(f)>(f).template operator()<false>();
}
}
// ...
constexpr_promote(verbose, []<bool VERB>{
add(3, 4, []<typename... Args>(std::format_string<Args...> msg, Args&&... args){
if constexpr (VERB)
std::print(msg, std::forward<Args>(args)...);
});
});
This is essentially the same code (there are two lambdas generated based on the two templates stamped out), but you don't need to repeat some stuff