Hello, my name is Jonathan Boccara. I'm your host on Fluent C++. I have been a C++ developer for 6 years, working for Murex which is a major software editor in the finance industry. My focus is on C++ and particularly how to write expressive code. I'm happy to take your feedback, don't hesitate to drop a comment on a post, follow me or get in touch directly !
Jonathan Boccara's blog
Today I want to share with you an interesting technique shown by Arthur O’Dwyer in his CppCon talk, Template Normal Programming, to deal with min and max on different types. Arthur has kindly accepted that I share this content with you on Fluent C++.
This will be a shorter post, fit for summer as you must be busy with your summer project. Or, less likely, busy sipping a cocktail on the beach. Or both.
Template Normal Programming is a series of two talks covering everything about templates in C++, except template metaprogramming. The talks are well structured and very progressive, and all backed up with excerpts from the standard. That’s a pretty impressive job, and Arthur manages to keep a presentation style that’s easy to follow. A worthy investment of two hours of your time, in short.
Now consider the following piece of code:
int x = 42;
return std::max(f(), x);
It doesn’t compile. Can you see why?
Take a moment to think about it! Can you see what is wrong with this piece of code?
Consider the declaration of
template< class T >
constexpr const T& max( const T& a, const T& b );
Notice that there is only one template parameter
And in the initial piece of code, the two parameters passed to
std::max are of different types: the first one is a
short and the second one is an
int. In a context without templates,
int are implicitly convertible to one another. Meaning that if we had either this declaration:
int const& max(int const& a, int const& b);
or this one:
short const& max(short const& a, short const& b);
The code would have compiled fine.
But the fact that the type is a template prevents implicit conversions. Put a different way, the template type deduction must exactly match the passed types.
If you faced this compilation error in your code, how would you go about fixing it?
The first solution that comes to mind is to force one argument in, with a cast:
int m = std::max(static_cast<int>(f()), x);
It’s not pretty, but it does the job.
Instead, consider this other alternative: working around the template deduction by specifying the type explicitly:
int m = std::max<int>(f(), x);
You say to
std::max that T is
int, and not to worry about deducing it from the parameters. This way we’re out of a deduction context and implicit conversion of
int can apply.
Now there is one good question about this technique: if the
short passed to
std::max is implicitly converted to an
int, this means that a temporary
int is created. And
std::max returns a reference to this temporary. Isn’t that a problem?
The answers depends on when the temporary is destroyed, and it is destroyed after the end of the full expression that contains it creation. And this full expression includes the copy of the value returned by
Here we’re good because we’re storing a copy (
int) of the value returned by
std::max. But had we stored a reference (
int const&) then it would have bound to a temporary and would thus be unusable on the following statement. Thanks to Björn and Arthur for helping me with these nuances.
Anyway, that’s one less cast in your code. And of course all of the above applies to
That’s it for this technique but there is much, much more to know about min and max in C++!
Related articles:    Don't want to miss out ? Follow: