This is a followup to C++ templates: prevent instantiation of base template
I use templates to achieve function overloading without the mess of implicit type conversions: declare the function template, define desired specializations (overloads). all is well except wrong code does not produce errors until the link phase:
lib.hpp:
template<class T> T f(T v);
lib.cpp:
#include "lib.hpp"
template<> long f(long v) { return -v; }
template<> bool f(bool v) { return !v; }
main.cpp:
#include <iostream>
#include "lib.hpp"
int main()
{
std::cout
<< f(123L) << ", "
<< f(true) << ", "
<< f(234) << "\n"
;
}
gcc output:
c++ -O2 -pipe -c main.cpp
c++ -O2 -pipe -c lib.cpp
c++ main.o lib.o -o main
main.o(.text+0x94): In function `main':
: undefined reference to `int get<int>(int)'
I'd like to have it fail during compilation of main.cpp. Can I somehow declare only specializations actually implemented?
What are my options? The target is C++03, and I'm mainly interested in gcc-4.x and VC9.
It seems to produce a linker error even if you don't put it in the separate file.
However, to produce a compiler error for other instantiations, implement the function and use a compile-time assertion, e.g
#include <boost/static_assert.hpp>
template <class T> T f(T)
{
//assert some type-dependent "always-false" condition,
//so it won't be triggered unless this function is instantiated
BOOST_STATIC_ASSERT(sizeof(T) == 0 && "Only long or bool are available");
}
template<> long f(long v) { return -v; }
template<> bool f(bool v) { return !v; }
int main()
{
//f(100);
f(100L);
f(false);
}
And just for general information, C++0x has a much more elegant way to deal with it:
template <class T> T f(T) = delete;
template<> long f(long v) { return -v; }
template<> bool f(bool v) { return !v; }
The best way is to implement that basic template with something invalid (not illegal) C++ code. For example,
template<class T> T f(T v) { return v.Default_Implementation_Not_Available; }
This error will be compile time; and it's generated only when you instantiate any version other than 'long' & 'bool'. If you don't instantiate 'int' version, compilation will go fine.
I don't believe it's possible to do what you want. See these FAQs for more info:
How can I avoid linker errors with my template functions?
How can I avoid linker errors with my template classes?
When compiling main.cpp, there's no way for the compiler to know which template specializations may exist in some other compilation unit -- so there's no way to flag this error at compile time, you have to wait until link time.