C++ Template Function Partial Specialization

Introduction

In the template function implementation, however, for certain data types, we do not have a common template function to call to perform some tasks. We would have to end up with specializing the template function multiple times for those data types and there could be a lot of code duplications in the implementation.

In C++17, there are some features added so that the code duplications in this scenario could be removed. In this blog post, I would like to quickly talk about this in this blog post.

Example

In the following examples, we want to create a template function add for different data types. “Unfortunately”, for int and float, we were restrained to perform add using int_add and float_add, respectively. Then, in addition to the template function T add(T a, T b), we would also have to create the specialization functions for int add(int a, int b) and float add(float a, float b), both of which could have lots of code duplications with the template function T add(T a, T b). This is not good in terms of maintaining the code.

C++14

Before C++14, we could do nothing to remove the code duplications in this scenario.

add_cpp14.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <type_traits>

float float_add(float a, float b)
{
std::cout << "Called float add." << std::endl;
return a + b;
}

int int_add(int a, int b)
{
std::cout << "Called int add." << std::endl;
return a + b;
}

template <typename T>
T add(T a, T b)
{
// Optionally do some heavy work.
// ...

return a + b;
}

float add(float a, float b)
{
// Optionally do some heavy work.
// ...

return float_add(a, b);
}

int add(int a, int b)
{
// Optionally do some heavy work.
// ...

return int_add(a, b);
}

int main()
{
int a = 1;
int b = 2;
int c{add(a, b)};
}
1
2
3
$ g++ add_cpp14.cpp -o add_cpp14 -std=c++14
$ ./add_cpp14
Called int add.

C++17

Since C++17, because constexpr if becomes supported, we could implement the add in the following fashion and the code duplications were removed.

add_cpp17.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <type_traits>

float float_add(float a, float b)
{
std::cout << "Called float add." << std::endl;
return a + b;
}

int int_add(int a, int b)
{
std::cout << "Called int add." << std::endl;
return a + b;
}

template <typename T>
T add(T a, T b)
{
// Optionally do some heavy work.
// ...

// constexpr if is a C++17 extension.
if constexpr (std::is_same_v<T, int>)
{
return int_add(a, b);
}
else if constexpr (std::is_same_v<T, float>)
{
return float_add(a, b);
}
else
{
return a + b;
}
}

int main()
{
int a = 1;
int b = 2;
int c{add(a, b)};
}
1
2
3
$ g++ add_cpp17.cpp -o add_cpp17 -std=c++17
$ ./add_cpp17
Called int add.

References

Author

Lei Mao

Posted on

07-22-2022

Updated on

07-22-2022

Licensed under


Comments