Restrict C++ Template Parameter to Subclass

Restrict C++ Template Parameter to Subclass

In this case you can do:

template <class T> void function(){
Baseclass *object = new T();

}

This will not compile if T is not a subclass of Baseclass (or T is Baseclass).

Can I specify that template arguments ought to be subclasses of some base class?

#include <type_traits>
#include <utility>

struct B { };
struct D : B { };

template <typename T>
struct S {
typedef typename std::enable_if<std::is_base_of<B, T>::value>::type check;
};

int main()
{
S<B> x; // Ok!
S<D> y; // Ok!
S<int> z; // Not ok!
}

The enable_if utility and the is_base_of type trait are part of the C++0x Standard Library, but both available in Boost as well.

C++ templates that accept only certain types

I suggest using Boost's static assert feature in concert with is_base_of from the Boost Type Traits library:

template<typename T>
class ObservableList {
BOOST_STATIC_ASSERT((is_base_of<List, T>::value)); //Yes, the double parentheses are needed, otherwise the comma will be seen as macro argument separator
...
};

In some other, simpler cases, you can simply forward-declare a global template, but only define (explicitly or partially specialise) it for the valid types:

template<typename T> class my_template;     // Declare, but don't define

// int is a valid type
template<> class my_template<int> {
...
};

// All pointer types are valid
template<typename T> class my_template<T*> {
...
};

// All other types are invalid, and will cause linker error messages.

[Minor EDIT 6/12/2013: Using a declared-but-not-defined template will result in linker, not compiler, error messages.]

How do I restrict a template class to certain built-in types?

One solution I've seen is to use std::enable_if in a type alias. Something like:

using value_type = typename std::enable_if<
std::is_same<float, RealType>::value ||
std::is_same<double, RealType>::value,
RealType
>::type;

value_type only exists if RealType is exactly float or double. Otherwise, the type is undefined and compilation fails.

I'd warn about being too strict with types, though. Templates are as powerful as they are partly because the duck typing they do means that any type that can be used the way you want to use it, will work. Disallowing types for the sake of disallowing types generally doesn't gain you much, and can make things less flexible than they could be. For example, you wouldn't be able to use a type with more precision, like a big-decimal type.

How to pass a templated function parameter with a subclass of the templated type in C++?

It is true that Derived is derived from Base, but that doesn't mean that A<Derived> must therefore be derived from A<Base>. C++ templates don't work this way.

All that A<Derived> is, is a class, instantiated by the A template. You could've simply declared:

class A_Derived {

// ...

};

With the same members (if it had any), and pretty much got the same results. Same for A<Base>. With nothing else in the picture, the two classes have absolutely nothing to do with each other, whatsoever. You can draw a mental picture here, as if you made the following declarations:

class A_Derived {

};

and

class A_Base {

};

Which is pretty much what this is history. Do you see A_Derived being explicitly derived from A_Base here? Obviously not. If something expects a reference or a pointer to A_Base, you cannot give it A_Derived, because the two classes have absolutely nothing to do with each other. They are independent classes.

P.S. You could declare an explicit specialization of A<Derived> as being derived from A<Base>, if you so wish, but specialization is a completely different topic...

How to elegantly restrict a template argument to be a `Certain_ClassAnyT`?

You can write a custom type trait is_specialization, as follows:

template<class Type, template<class...> class Template>
struct is_specialization
: std::false_type {};
template<template<class...> class Template, class... TArgs>
struct is_specialization<Template<TArgs...>, Template>
: std::true_type {};

Then you just need to static_assert that is_specialization is true for the given template argument:

template<class T,class T2>
class Wrapper {
static_assert(is_specialization<T2, MyArray>::value, "T2 must be a specialization of MyArray");
};

Restrict generic parameter on interface to subclass

You can't enforce that at compile-time, because .NET generics don't have template specialization or duck typing.

You can, however, include a static constructor (type initializer) that uses reflection to assert the relationship at load time. Ok, C# doesn't allow you to put a static constructor on an interface (even though .NET does allow it), so you would need to use a module initializer or a function you call yourself. Also, you would need to search for types implementing the interface, including types that aren't loaded yet (you can subscribe to the Assembly.Load event to be notified of types loaded in the future).

C++ subclassing in template parameters

C++ template specialization is based off pattern matching. It does not use inheritance.

template <typename T1, typename T2> class C<T1, B1<T2> >

only matches B1, As far as the above is concerned, B2 is an unrelated type. Your error happened long before the doSomething code, it is a red herring for now.

The first thing to do is fix the above snippet:

template <class T1, template<class>class B, class T2>
class C<T1, B<T2> >

now it pattern matches both B1 and B2. Next do the same to doSomething:

template <class T1, template<class>class B, class T2>
int doSomething(C<T1, B<T2> >& c)

and the code should work.

Further restriction can be done via SFINAE if needed.



Related Topics



Leave a reply



Submit