Function templates - deduce template arguments or pass explicitly?

Function templates allow writing a single definition that can handle multiple different types. It is a very powerful form of C++’s static polymorphism.

When instantiating a class template, we have to pass in the types explictly (at least until C++17):

std::vector<int> vec;
std::basic_string<my_char, std::char_traits<my_char>> str;
std::tuple<int, bool, std::string> tuple;

But when instantiating a function template, the compiler can often figure the types out:

template <typename A, typename B, typename C>
void func(const A& a, const B& b, const C& c);

int x;
func(x, 'A', "hello");
// equivalent to:
func<int, char, const char*>(x, 'A', "hello");

Let’s look at this process into a little bit more detail and establish some guidelines as well as see how we can prohibit template argument deduction for arguments.

» read more »
Author's profile picture Jonathan

void foo(T& out) - How to fix output parameters

There are some cases where you need to return a value from a function but cannot use the return value. It happens, for example, in functions where you want to return multiple values at once. While you can pass multiple inputs to a function - the parameters, you cannot pass multiple return values in the same way.

C++ programmers tend to use a good old (lvalue) reference for that. You take a non-const reference as parameter and assign the output to that reference. The caller will pass a variable and upon function completion find the value of the variable changed.

Yet this approach has some problems: For starters, it is not obvious when just looking at the call that the variable is going to be changed. This is the reason that C++ style guides such as the one used by Google recommend using a pointer for that. The caller then has to explicitly pass in the address of the variable, making it explicit.

But with a pointer you can now pass in nullptr, you have to check for that in the function: A pointer where you really mean “reference” does not follow the guidelines I’ve been advocating for.

So is there not a universal solution?

There is, but first we need to understand the full scope of the problem.

» read more »
Author's profile picture Jonathan

Tutorial: Emulating strong/opaque typedefs in C++

Last week, I’ve released my type_safe library. I described it’s features in the corresponding blog post but because the blog post got rather long, I couldn’t cover one feature: strong typedefs.

Strong or opaque typedefs are a very powerful feature if you want to prevent errors with the type system

  • and as I’ve been advocating for, you want that. Unlike “normal” typedefs, they are a true type definition: they create a new type and allow stuff like overloading on them and/or prevent implicit conversions.

Sadly, C++ doesn’t provide a native way to create them, so you have to resort to a library based emulation.

BTW, type_safe received a couple of requested features: There are improvements to the monadic optional functions (bind(), map(), unwrap() as well as a new transform()), multi-visitation of optionals and ArithmeticPolicy to control over/underflow behavior of the ts::integer<T>.

» read more »
Author's profile picture Jonathan

Type safe - Zero overhead utilities for more type safety

Two weeks ago I’ve blogged about using C++’s type system to prevent errors. The post spawned a lot of discussion so I wanted to address some of the responses I’ve got. I’ve also said at the end of the post that I was going to write a library that helps to implement the techniques. The library is now done - type_safe can be found on Github, but please do read on for a discussion about the motivation and feature overview.

» read more »
Author's profile picture Jonathan