Skip to content

Instantly share code, notes, and snippets.

@tristan0x
Last active October 9, 2022 11:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tristan0x/540146c104c29ef607071b8f498b7d20 to your computer and use it in GitHub Desktop.
Save tristan0x/540146c104c29ef607071b8f498b7d20 to your computer and use it in GitHub Desktop.
How to use C++ explicit instantiation to hide implementation of template class or member

Rationale

This gist highlights the fact that implementation of C++ template symbols do not necessary have to be available where there are used.

File Layout

  • foo.hh: Provide template class Foo declaration
  • foo.cc: Provide template class Foo definition + explicit instantiation of Foo<int>
  • bar.cc: Provide main function using Foo<Foo_TYPE> where FOO_TYPE is a macro with int as default value.

Usage

Run make to successfully build the main executable despite compiler does not know implementation of Foo::incr when compiling bar.cc

$ make
g++ -Wall -ansi -pedantic -Werror   -c -o foo.o foo.cc
g++ -Wall -ansi -pedantic -Werror   -c -o bar.o bar.cc
g++ foo.o bar.o -o main

Run CPPFLAGS="-DFOO_TYPE=double" make distclean all to see that bar.cc compilation passes but linkage doesn't.

$ CPPFLAGS="-DFOO_TYPE=double" make distclean all
rm -f foo.o bar.o
rm -f main
g++ -Wall -ansi -pedantic -Werror -DFOO_TYPE=double  -c -o foo.o foo.cc
g++ -Wall -ansi -pedantic -Werror -DFOO_TYPE=double  -c -o bar.o bar.cc
g++ foo.o bar.o -o main
bar.o: In function `main':
bar.cc:(.text+0x33): undefined reference to `Foo<double>::incr(double const&)'
collect2: error: ld returned 1 exit status
Makefile:7: recipe for target 'main' failed
make: *** [main] Error 1
#include "foo.hh"
#ifndef FOO_TYPE
# define FOO_TYPE int
#endif
int main() {
Foo<FOO_TYPE> f;
return f.incr(-1);
}
#include "foo.hh"
// definition of Foo::incr
template <typename T>
T Foo<T>::incr(const T& x) {
return x + 1;
}
// explicit instantiation for type int
template class Foo<int>;
template <typename T>
class Foo {
public:
T incr(const T& x);
};
SOURCES = foo.cc bar.cc
CXXFLAGS = -Wall -ansi -pedantic -Werror
all: main
main: $(SOURCES:.cc=.o)
$(CXX) $? -o $@
clean:
$(RM) $(SOURCES:.cc=.o)
distclean: clean
$(RM) main
depend:
makedepend $(SOURCES)
# DO NOT DELETE
foo.o: foo.hh
bar.o: foo.hh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment