Mixing C++ Template Specialization with Non-template Overloads - Who Wins ?

As C++ developers, we often use overloaded functions when we have different logic to handle different types of data, so we write a separate implementation per type. The down-side of this approach is that we don’t have a fallback implementation that applies as a default to the types for which we don’t have implementation.

Code

That’s why we have template functions. Templates are used when we have the same logic to handle different types of data. If we need to handle all the types with the same logic, except a few types that must be handled with a different logic, then we use template specialization.

Code

However, when we start mixing overloaded functions with template specialization, things start to become blurry.

I’ll give the example below, think of it, then I will tell you the rules the compiler uses to decide if it is going to pick up the non-template overload function, the primary template or the specialized template:

Code

Let’s see how does the compiler choose which function to use in our example:

  • The compiler lists all the viable candidate functions (all non-template overloaded + primary templates. Template specializations are totally ignored in this stage).
  • If a non-template function with exactly the same type is found without type conversion, the compiler chooses it. Even if there is an exact match with template specialization. As we said, specialization is not considered at this stage.
  • If not found, the compiler considers the template function:
  • If there is a template specialization with exactly the same types (no conversion), the template specialization is called. Otherwise, the primary template is used.
  • If there are no template functions, the compiler chooses the non-template overload with type promotion (which is an automatic type conversion that the compiler does, like char -> int, float -> double).
  • If there are no non-template overload with type promotion, the compiler chooses a non-template overload with standard type conversion (like float -> int).
  • If there is no such non-template with standard conversion, the compiler chooses a non-template with user defined conversion (like converting char * to std::string)
  • If no such function, it is time to raise an error.

This means that:

  • Exact matching non-template beats exact-matching template specialization.
  • Exact matching template specialization beats primary template.
  • Primary template beats non-template overload with type promotion.
  • Non-template overload with type promotion beats non-template overload with standard conversion.

It is also very important to know that:

  • Template specializations are never competing with overload resolution.
  • Template specializations are selected only and only if they have an exact match.
  • They are never selected with conversion.
  • Template specialization always follow a primary template. Specialization without a primary template is not possible.
  • Non-template overloads may be selected for implicit or standard conversion (if no exact match with non-template, and there is no template)
  • Template specializations are only considered if type deduction of their their primary template is done, then the compiler checks if there is a better special implementation with T=type_in_question.

Applying these rules to the example:

  • foo(i) -> Exact type match with non-template -> non-template int.
  • foo(f) -> Non-template foo(double) could match, but involves type promotion, so the compiler considers template. There’s no template specialization with double -> primary template.
  • foo(d) -> Same logic as foo(i) -> non-template double.
  • foo(s) and foo(cs) -> MyStr is typedefded to const char*, so they’re treated the same. No exact non-template, so the compiler goes to template. There’s an exact match template specialization -> specialized const char*.
  • foo(cf) and foo(ps) -> Same logic as foo(f), no non-template exact match, check template, no exact match template specialization -> primary template.

Related Content