I would separate the implementation and the interface, using template specialization:
lib1.h:
#include <iostream>
template <int T> void print_me(void);
template <> void print_me<0>(void);
template <> void print_me<1>(void);
lib1_internal.h (NOTE: this does not need to be disclosed):
#include <iostream>
template<int N>
void print_me_internal() {
std::cout << "I am function number " << N << std::endl;
}
lib1.cpp:
#include "lib1.h"
#include "lib1_internal.h"
template <> void print_me<0>() {
print_me_internal<0>();
}
template <> void print_me<1>() {
print_me_internal<1>();
}
your main.cpp will correctly lead to a linker error:
$ g++ main.cpp -L. -l1
/tmp/ccZSDqkp.o: In function `main':
main.cpp:(.text+0xf): undefined reference to `void print_me<2>()'
collect2: ld returned 1 exit status
Just add the definition of template <int T> void print_me(void)
in lib1.h
in place of its declaration and it will be used whenever not found in the specialized versions.