Effective C++ item 44: Factor Parameter-independent code Out of Templates

You probably heard of code bloat or object bloat when using templates. It is caused by instanciate too many versions of the same template for different types, causing object file to become very big while source code looks slim. Let’s see an example

1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename T, std::size_t n>
class SquareMatrix {
public:
void invert(){}
};

int main() {
SquareMatrix<double, 5> sm1;
sm1.invert();
SquareMatrix<double, 10> sm2;
sm2.invert();
return 0;
}

If you compile above code and inspect the symbol table, you will find out that two versions of functions are generated, one for size 5 matrix and one for size 10 matrix.

1
2
3
4
5
$ nm main.o | c++filt
nm main.o | c++filt
0000000000000040 T SquareMatrix<double, 10ul>::invert()
0000000000000030 T SquareMatrix<double, 5ul>::invert()
0000000000000000 T _main

A better design will be using private inheritance to share implementation, which is exactly why private inheritance exists(refer to item39).

1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename T>
class SquareMatrixBase {
protected:
void invert(std::size_t matrixSize){}
};

template<typename T, std::size_t n>
class SquareMatrix: private SquareMatrixBase<T> {
private:
using SquareMatrixBase<T>::invert;
public:
void invert() {this->invert(n);}
};

Now if we look at the symbol table again, you will see that the actual implementation of invert is shared in the version of SquareMatrixBase<double>::invert(unsigned long).

1
2
3
4
5
6
$ nm main.o | c++filt
nm main.o | c++filt
0000000000000090 T SquareMatrixBase<double>::invert(unsigned long)
0000000000000060 T SquareMatrixBetter<double, 10ul>::invert()
0000000000000030 T SquareMatrixBetter<double, 5ul>::invert()
0000000000000000 T _main

Code bloat is often an issue when coding in templates and somethimes difficult to predict before you look at object file size. In non-template code, replication is explicit: you can see that there’s duplication between two functions or two classes. In template code, replication is implicit: there’s only one copy of the template source code, so you have to train yourself to sense the replication that may take place when a template is instantiated multiple times.

Reference:
“Effective C++” Third Edition by Scott Meyers.