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

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.

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*>;

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!

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.

Concepts were removed from '0x. You can use a library, like Boost Concept Check.

"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

boost::enable_if

Related

How to prevent specialization of a C++ template?

The compiler doesn't complain when I do this ;-)
// Myfile.h
#include <iostream>
#include <vector>
namespace std
{
template<> class vector<int>
{
public:
vector ()
{
std::cout << "Happy Halloween !!!\n";
}
};
}
Is there any way to prevent this kind of undesirable specialization of a class/function template?
--EDIT--
I just used std:: as an example. What I'm looking for is a way to prevent this from happening to any template class.
What you do is specialize a standard library type inside a standard namespace.
Except for a few documented customization points (std::swap, std::hash<>) or specificly constrained specializations for User Defined Types (e.g. MySmartPtr<T>) this is against the specification and the result is undefined behaviour.
Edit: There is no mandatory diagnostic for this kind of rule violation.
To make it marginally harder for clients of your library to mess things up, you can do this trick:
namespace Public {
namespace Hidden { // DON'T TOUCH THESE!
template <typename> struct MyType { };
}
using Hidden::MyType;
}
Now, attempting to specialize MyType<> in namespace Hidden will fail.
No, the C++ language does not provide a general mechanism by which you can say "don't allow specializations of this template".
But it may not matter. For any instantiation that your code uses already, a user provided specialization will violate the one definition rule and their program may blow up in a fireball.
If you aren't using the instantiation in your library then what they do doesn't matter.
This is one of the cases where in C++ you simply can't prevent your user from shooting themself in the foot and if they choose to do so the responsibility is on them.
An alias template can not be specialized and has the behaviour you need for class templates.
template<class T>
struct my_class_implementation_which_should_not_be_used_directly
{
// impl
};
template<class T>
using my_class = my_class_implementation_which_should_not_be_used_directly<T>;
In addition you should document that specialising my_class_implementation_which_should_not_be_used_directly results in undefined behavior. Now your libraries user can not specialize my_class accidentally and is warned about the class with the ugly name directly.
Edit:
You can prevent specializations of your templates with enable_if in C++11. This is impractical though.
#include <type_traits>
template<
typename real_t,
typename = typename std::enable_if<
std::is_floating_point<real_t>::value
>::type
>
struct check_t;
template<
typename real_t,
typename = typename
std::enable_if<
std::is_floating_point<real_t>::value,
check_t<real_t>
>::type
>
class vec_t
{
};
#if 1
template<>
class vec_t<int> {};
template<>
class vec_t<int,check_t<int>> {};
#endif
void test()
{
vec_t<float> vecf;
vec_t<int> veci;
}
link
main.cpp:26:16: error: no type named 'type' in 'struct std::enable_if<false, void>'
The best way to prevent such behavior is through coding standards and code review.
You cannot force the compiler into an error in this case (other than using workarounds like those suggested in other answers), because that behavior is actually allowed by the language, although it's real usefulness can be questioned.
The matter is - it is very possible that you want/need to provide a generic behavior for multiple types (hence the use of templates) but you need to provide a specific implementation for some of the allowed types (notably std::string)
A quick & dirty example (it's a function, but the same could apply to classes) could be the following:
template<typename TData> TData GetData(std::string argument)
{
std::stringstream stream;
TData retVal;
stream.str(argument);
stream >> retVal;
return retVal;
}
However this is going to fail with std::string, as the >> operator would stop after the first blank space. So you could provide a dedicated specialization.
template<> std::string GetData(std::string argument)
{
return argument;
}
There are a few ways to go about this. You can declare specific specializations without defining them. eg:
template<> struct MyStruct<int>;
That way, if someone tries to instantiate with an int, they would get this specialization and it won't compile because there is n definition. Then you can write a simple macro to do this for all the types you don't want a specialization for.
For the inverse of this, make the definition empty:
template<typename T> struct MyStruct{};
Then define the specific types you plan to support:
template<> struct MyStruct<int> {...};
template<> struct MyStruct<std::string> {...};
//etc...

Inheritance gadget for type member in standard?

When programming with C++ templates, I often find it useful to define a type alias member called type. I've defined a kind of "identity" template:
template <typename T>
struct id { using type = T; };
I quite like that I can then often avoid putting anything between the braces of a class definition; inheriting from an id specialisation instead. A trivial primary template example might then be:
template <typename,typename>
struct Foo : id<void> {};
Does something like id exist in the standard library; or Boost?
yes, sort of.
std::enable_if<true, T>

Partial specialization with type nested in a templated class

I'm playing with templates and partial specialization, but there is one specialization I don't know how to write... I'll simplify code to make it easier to read.
Let's condiser
template <typename T>
class x
{
...
};
Usually, I can specialize like this :
class x<a_type>
{
...
};
Also works with templates types :
template <typename T>
class x<std::vector<T>>
{
...
}
Now I would like to make the specialization for a type nested in a templated class:
template <typename T>
class y
{
struct nested_type
{
y a_member;
};
...
};
// Here comes the specialization
template <typename T>
class x<y<T>::nested_type>
{
...
};
This fails. I also tried to put 'typename' before y::nested_type but it did not solved the problem. Compiler error is:
type/value mismatch at argument 1 in template parameter list for ‘template <class T> struct x’
What I want to do seems logical, but I'm not sure if it is possible. I'm using C++0x with g++-4.5. Does anybody know the correct syntax to write such specialization ?
The answer is that you cannot do this specialization. It is not a syntax error, but just something that cannot be realized. You have to see template specializations a little bit like function overloading. The compiler has to take the type argument at the use-site, look at the specializations available, find matches, and select the best one (most specialized one). The problem with your example is that the "find match" step cannot be realized with such a specialization. The compiler can expect "nested_type" to be anything, not necessarily a unique type (as it is in your example), it could also be a nested typedef, for instance. Moreover, the compiler cannot predict that it is already seeing all the specializations of template "y", so even if nested_type is a unique type nested in y (general template), it could be a nested typedef in an upcoming template specialization declaration for template "y".
Just like with function overloading and the matching algorithm used there, the compiler is limited in its capabilities to deduce the type, and what limits it is how much assumptions it can make. If you have a specialization for x<int> and later use x<int>, the match is trivial, no deduction needed, no assumptions needed. If you have a specialization like x<T*> and later use x<int*>, the match is easy, T can be deduced to be int. If you have a specialization like x< y<T>::type > and then use any version of x, how is the compiler supposed to deduce T from y::type? It would have to substitute for T in y all the possible types that exist in the entire world to see if there is one that results in a matching nested type. That's an unreasonable expectation, and that is why the type deduction capabilities of C++ templates stop here. Very often, to know if you should expect the compiler to be able to resolve something, just put yourself in its shoes and see if it is even remotely possible (the answer is usually clear).
You cannot do this partial specialization indeed, but there is a workaround which you can use the achieve desired effect.
Instead of specialization, force the target type to implement what you need.
Here is a minimal example for that:
#include <vector>
#include <iostream>
#include <cassert>
// Default template defines an interface against the target type.
template <class T> struct Traits
{
using TraitsType = typename T::foo_type;
static void foo()
{
T::foo();
}
};
// This is the sample class.
template <class T> struct MyStuff
{
struct NestedType
{
int x;
// It implements the desired features.
using foo_type = int;
static void foo()
{
std::cout << "Using Nested version!\n";
}
};
};
// For built in types you can use specialization.
template <> struct Traits<int>
{
using TraitsType = double;
static void foo()
{
std::cout << "Using int version.\n";
}
};
//... If you can't touch the nested type, the you are SOL.
int main()
{
static_assert(std::is_same<Traits<int>::TraitsType, double>::value);
static_assert(std::is_same<Traits<MyStuff<int>::NestedType>::TraitsType, int>::value);
static_assert(std::is_same<Traits<MyStuff<double>::NestedType>::TraitsType, int>::value);
Traits<int>::foo(); // Prints "Using int version"
Traits<MyStuff<int>::NestedType>::foo(); // Prints "Using Nested version!\n"
Traits<MyStuff<double>::NestedType>::foo(); // Prints "Using Nested version!\n"
return 0;
}

Template partial specialization

Would any one knows according to what rules code below doesn't compile?
template <class T>
struct B
{
typedef T type;
};
template<class T>
struct X
{
};
template<class T>
struct X<B<T>::type*>//HERE I'M PARTIALLY SPECIALIZING (WELL, TRYING TO...)
{
};
Please see comment inside the code.
How do you think that will work? The compiler will look to see if there is a class T somewhere that has a typedef "type" to your class?
It just won't. Even though it's a pointer.
Remember that presumably your B template is presumably specialised in places so that type is not always T*, but it can't deduce it with reverse engineering.
For those who did not understand my answer fully, what you are asking the compiler to do is find a class U such that B::type is the class you pass in as a parameter.
class Foo;
class Bar;
template<> struct B<Foo>
{
typedef int type;
};
template<> struct B<Bar>
{
typedef int type;
};
X<int*> // ambiguous, T is Foo or Bar?
It is difficult to know exactly why you are trying to do what you are. You can do a partial specialization on all pointers and then a total specialization on specific pointers, which could be implement in terms of another template.
You need to use typename keyword as,
template<class T>
struct X<typename B<T>::type*>
{
};
It's because B<T>::type is a dependent name. So typename is required!
--
EDIT:
Even after putting typename, it isn't compiling. I think it's because deduction of type T in B<T> from X<U> is difficult, or possibly impossible, for the compiler. So I believe its non-deduced context.
See a similar example here and the discussion:
Template parameters in non-deduced contexts in partial specializations
However, if you change the specialization to this:
template<class T>
struct X<B<T> >
{
};
Then it becomes the deducible context, and so would compile.
Assuming you already added typename as suggested by Nawaz.
The problem is exactly explained in the error message you encounter: "template parameter is not deducible in partial specialization B<T>::type*. The problem is that B<T>::type and T is exactly the same for all types T. Consider the following example:
class MyClass1 {};
typedef typename B<MyClass>::type MyClass2; //(*)
X<MyClass*> obj1;
X<MyClass2*> obj2;
The result of line (*) is a type MyClass2 which is essentially MyClass1. So, obj1 and obj2 should be objects of the same class. Now, which version of template X should they use?
If you would expect the specialised version of X, tell me if the answer should be the same if line (*) is removed (and obviously obj2 as well). Still obj1 should be the specialised version of X as line (*) has nothing to do with it.
But now we expect the compiler to detect that some type can be potentially declared as B<T>::type although we never do this. We expect the compiler to verify all possible template instantiations to check if there is no strange typedef in one of them.
I hope this clarifies why such specialisation cannot be handled by the compiler.
An alternative that might help
I believe your problem could be attacked by creating a trait class for explicitly marking types that should be handled in a special way. Something like this:
template <bool v>
struct boolean_value {
static const bool value=v;
};
template <typename T>
struct is_my_interesting_type : public boolean_value<false> {};
class MyClass {
...
};
template <>
struct is_my_interesting_type<MyClass> : public boolean_value<true> {};
template <typename T, bool special>
class InternalX {
... //generic version of your template X
};
template <typename T>
class InternalX<T,true> {
... //special version of your template X
};
template <typename T>
class X : public InternalX<T,is_my_interesting_type<T>::value> {};
Also, you might be interesting how it is done in boost library, in particular Boost.Type_Traits
"The argument list cannot be identical to the non-specialized argument list (it must specialize something)"
see partial_specialization at en.cppreference.com

C++ creating generic template function specialisations

I know how to specialise a template function, however what I want to do here is specialise a function for all types which have a given method, eg:
template<typename T> void foo(){...}
template<typename T, if_exists(T::bar)>void foo(){...}//always use this one if the method T::bar exists
T::bar in my classes is static and has different return types.
I tried doing this by having an empty base class ("class HasBar{};") for my classes to derive from and using boost::enable_if with boost::is_base_of on my "specialised" version. However the problem then is that for classes that do have bar, the compiler cant resolve which one to use :(.
template<typename T>
typename boost::enable_if<boost::is_base_of(HasBar, T>, void>::type f()
{...}
I know that I could use boost::disable_if on the "normal" version, however I do not control the normal version (its provided by a third party library and its expected for specialisations to be made, I just don't really want to make explicit specialisations for my 20 or so classes), nor do I have that much control over the code using these functions, just the classes implementing T::bar and the function that uses it.
Is there some way to tell the compiler to "always use this version if possible no matter what" without altering the other versions?
EDIT: I tried a different approach using a template class and explicit specialisations, but this is apparently also not allowed...Anyway to make this approach work?
template<typename T>class ImpFoo
{
public:
//error C3637: 'foo' : a friend function definition cannot be a specialization of a function template
template<> friend void foo<T>(){...}
};
...
class SomeClass : public ImpFoo<T>
{
...
SomeType bar(){...}
};
Sadly you are out of luck in this situation as descriped, the best thing you can do is to explicitly specialize the templates as #aaa says.
As you can limit these specializations to a simple forwarding to one central function, the overhead for 20 classes should be bearable. E.g.:
template<class T> my_foo() { /* do the actual work */ }
template<> void foo<MyClass01>() { my_foo<MyClass01>(); }
// ...
template<> void foo<MyClass20>() { my_foo<MyClass20>(); }