Tuesday Coding Tip 08 — Explicit template specialization

posted Originally published at medium.com 2 min read

Tuesday coding tips are super short posts about various tidbits mainly from C++, but also from other programming languages I use. You can also follow the #TuesdayCodingTips hashtag on Mastodon and Linkedin.


While template instantiation can be used to move your template implementation from header files to object files for a given subset of types, specialization allows you to override the default template implementation for a particular type.

Specialization requires that you first define the template implementation and then you can implement any number of specializations for given types. This way, you can override free functions (while maintaining their overall signature) or you can override whole classes (and you don’t have to respect their interfaces). This way, you can create drop-in replacements for library containers specialized for particular types and try to optimize them for your use case.

#include <filesystem>
#include <iostream>
#include <string>

template<class T>
T concat(T a, const T& b)
{
    return a + b;
}

namespace fs = std::filesystem;

fs::path concat(fs::path a, const fs::path& b)
{
    return a / b;
}

int main()
{
    using namespace std::string_literals;
    std::cout << concat("aaa"s, "bbb"s) << std::endl;        // outputs: aaabbb
    std::cout << concat("aaa", "bbb").string() << std::endl; // outputs: aaa\bbb
    return 0;
}

The specialization can also be partial and it can be inline/const whatever even if the original template is not.

#include <iostream>
#include <string>

template<class T>
struct CustomType
{
    T foo() { return T {}; }
};

template<>
struct CustomType<std::string>
{
    std::string bar() { return "hello world"; }
};

int main()
{
    CustomType<int> ct1;
    std::cout << ct1.foo() << std::endl; // outputs: 0
    CustomType<std::string> ct2;
    std::cout << ct2.bar() << std::endl; // outputs: "hello world"
}

Last but not least, if you’re implementing a template and need to change only a few lines of implementation for one particular type, you don’t need specialization. Instead, use constexpr conditions — they are evaluated in compile time and optimized away when the compiler emits its own specialized code.

#include <concepts>
#include <filesystem>
#include <iostream>
#include <string>

template<class T>
T concat(T a, const T& b)
{
    if constexpr (std::is_same_v<T, std::filesystem::path>)
        return a / b;
    else
        return a + b;
}

int main()
{
    using namespace std::string_literals;
    using path = std::filesystem::path;
    std::cout << concat("aaa"s, "bbb"s) << std::endl; // outputs: aaabbb
    std::cout << concat(path{ "aaa" }, path{ "bbb" }).string()
              << std::endl; // outputs: aaa\bbb
    return 0;
}

1 Comment

0 votes

More Posts

Tuesday Coding Tip 06 - Explicit template instantiation

Jakub Neruda - Apr 7

Tuesday Coding Tip 02 - Template with type-specific API

Jakub Neruda - Mar 10

Tuesday Coding Tip 05 - Object initialization in C++

Jakub Neruda - Mar 31

Tuesday Coding Tip 10— CTest

Jakub Neruda - May 5

Tuesday Coding Tip 09 — Source location

Jakub Neruda - Apr 28
chevron_left

Related Jobs

Commenters (This Week)

19 comments
12 comments
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!