Sometimes when coding with C++ templates, you want to prevent users from instantiating a specific specialization or set of specializations, because the result would be nonse
If you don't want to use a library, this construct is pretty reliable (it's roughly what Boost does internally):
template <typename T>
void must_be_specialized(T const&)
{
enum dummy { d = (sizeof(struct must_be_specialized_for_this_type)
== sizeof(T)) };
}
You can put something analogous in a specialization to disallow instantiation of the template with that type. I wouldn't, personally, worry about must_be_specialized_for_this_type
gaining a definition from somewhere, but you could use a forward declaration to squirrel it away in a private namespace if you really wanted.
"Are there better straightforward ways to disallow template instantiations?" Nothing significantly better than what you have already identified. I am pretty sure C++ protection mechanisms are there to protect you from accident not from malice. And someone defining a specialisation or a class to break your intended use I would consider malicious. Perhaps you could hit the person in the back of the head each time they do it.
I personally prefer to put the checks into templates that exist only to describe the checks. That allows interesting combinations of inheritance and templates.
template <class T>
class not_with_pointer_t { };
template <class T>
class not_with_pointer_t<T*>;
template <class T>
class some_class_t : public not_with_pointer_t<T> { };
template <class T, template <class U> class base_t>
class another_class_t : public base_t<T> { };
typedef some_class_t<int> a_t; // ok
typedef some_class_t<void*> b_t; // error if instantiated
typedef another_class_t<void*, not_with_pointer_t> c_t; // error if instantiated
template <class T> class unrestricted_t { };
typedef another_class_t<void*, unrestricted_t> d_t; // ok
For me this sounds like a typical case for static_assert from C++0x or BOOST_STATIC_ASSERT. The static_assert functionality has the advantage that you can pass a custom error message so that the reason for the error is more clear.
Both ways are giving you the opportunity to prematurely end the compilation process under some custom defined compile time condition.
with static_assert:
template <typename T> struct MyClassTemplate<T*> {
static_assert(always_false<T>::value, "Do not use MyClassTemplate with a pointer type!");
};
with BOOST_STATIC_ASSERT
template <typename T> struct MyClassTemplate<T*> {
// Do not use MyClassTemplate with a pointer type!
BOOST_STATIC_ASSERT(always_false<T>::value);
};
Always false would look something like this:
template< typename T >
struct always_false {
enum { value = false };
};
HTH
Edit: Fixed the examples to make them actually work ;-) Thanks to GMan!
Concepts were removed from '0x. You can use a library, like Boost Concept Check.
You could just omit defining it.
template <typename T> struct MyClassTemplate<T*>;
You could also derive from a non-defined specialization
template <typename T> struct invalid;
template <typename T> struct MyClassTemplate<T*> : invalid<T> { };
Note that explicit specializations that declare classes or functions will never depend on template parameters. So, stuff like this that depend on template parameters can't work anyway. In that case, declaring a non-defined explicit specialization should be sufficient
template<> struct MyClassTemplate<int*>;
boost::enable_if