Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to intentionally cause a compile-time error on template instantiation

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 nonsensical. So you can define a (specific or partial) specialization whose definition, if instantiated, would cause a compiler error. The goal would be, if a user "misuses" the template, to cause a compiler error right next to a comment in your header file explaining what not to do, rather than leaving the compiler to come up with some confusing error message by its own devices, or maybe allowing the questionable code to compile.

Example:

template <typename T> struct MyClassTemplate {   // ... };  template <typename T> struct MyClassTemplate<T*> {   // Do not use MyClassTemplate with a pointer type!   typedef typename T::intentional_error err; }; 

There are a number of ways to do this (depending on whether your specialization is a complete or partial specialization of a class or function). But the syntax used must (?) depend on a template parameter, or else the compiler will complain when it first parses the intentional-error definition. The example above has a hole in that somebody could stubbornly define an intentional_error nested type or member typedef (though I'd say they would then deserve whatever problems come up as a result). But if you use a trick too fancy, you're likely to get an indecipherable and/or misleading compiler error message, which mostly defeats the purpose.

Are there better straightforward ways to disallow template instantiations?

I'm aware that in C++0x, template Concepts and deleted function declarations will provide much better control over this sort of thing, but I'm looking for answers that are valid C++03.

like image 759
aschepler Avatar asked Oct 13 '10 18:10

aschepler


People also ask

Are templates instantiated at compile-time?

7.2. Instantiation is the process by which a C++ compiler creates a usable function or object from a template. The C++ compiler uses compile-time instantiation, which forces instantiations to occur when the reference to the template is being compiled.

How do I force a template instantiation?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.

What is an example of a compile error?

Examples of compile-time errors include: missing parenthesis, missing a semicolon, utilizing undeclared variables, etc. All these errors are detected at compile-time and the compiler shows the respective error during the compiling.

Can a program compile with errors?

Compilation error refers to a state when a compiler fails to compile a piece of computer program source code, either due to errors in the code, or, more unusually, due to errors in the compiler itself. A compilation error message often helps programmers debugging the source code.


2 Answers

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*>; 
like image 101
Johannes Schaub - litb Avatar answered Sep 20 '22 10:09

Johannes Schaub - litb


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!

like image 37
Vinzenz Avatar answered Sep 24 '22 10:09

Vinzenz