An explicit specialization of a function template is inline only if it is declared with the inline specifier (or defined as deleted), it doesn't matter if the primary template is inline.
Key differences between generics and C++ templates: Generics are generic until the types are substituted for them at runtime. Templates are specialized at compile time so they are not still parameterized types at runtime. The common language runtime specifically supports generics in MSIL.
To do so, we can use a function template specialization (sometimes called a full or explicit function template specialization) to create a specialized version of the print() function for type double.
There is no difference. typename and class are interchangeable in the declaration of a type template parameter.
Though it is an old and outdated question, it may worth noting that C++11
had solved this issue using deleted functions:
template<typename T>
T GetGlobal(const char *name) = delete;
template<>
int GetGlobal<int>(const char *name);
UPDATE
This will not compile under MacOS llvm 8
.
It is due to a still hanging 4 years old defect (see this bug report).
The following workaround will fit the issue (using a static_assert
construct).
template<typename T>
T GetGlobal(const char *name) {
static_assert(sizeof(T) == 0, "Only specializations of GetGlobal can be used");
}
template<>
int GetGlobal<int>(const char *name);
UPDATE
Visual studio 15.9 has the same bug. Use the previous workaround for it.
To get a compile-time error implement it as:
template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined
If you use Boost you could make it more elegant:
template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
C++ Standard guarantees that there is no such type which has sizeof equal to 0, so you'll get a compile-time error.
As sbi suggested in his comments the last could be reduced to:
template<typename T>
T GetGlobal(const char *name) { char X[!sizeof(T)]; }
I prefer the first solution, because it gives more clear error message (at least in Visual C++) than the others.
If you don't implement it, you'll at least get a linker error. If you want a compile-time error, you could do this with class templates:
template<typename T>
struct GlobalGetter;
template<>
struct GlobalGetter<int> {
static int GetGlobal(const char *name);
};
template<>
struct GlobalGetter<double> {
static double GetGlobal(const char *name);
};
template<typename T>
T GetGlobal(const char *name)
{
return GlobalGetter<T>::GetGlobal(name);
}
I would suggest not to actually provide an implementation, just a bare declaration of the method.
The other option would be to use a compile-time assert. Boost has a number of such beasts.
namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
boost::same_type<T, int> >));
There is also its message version counterpart, which would help.
The following are alternative techniques to using boost:
Declare a typedef to a dependent name
This works because name lookup for DONT only occurs when 'T' has been replaced. This is a similar (but legal) version of the example given by Kirill
template <typename T>
T GetGlobal (const char * name) {
typedef typename T::DONT CALL_THIS_FUNCTION;
}
Use an incomplete return type
This technique doesn't work for specializations, but it will work for overloads. The idea is that its legal to declare a function which returns an incomplete type, but not to call it:
template <typename T>
class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With