How to Ensure That the Template Parameter Is a Subtype of a Desired Type

How to ensure that the template parameter is a subtype of a desired type?

Given some complete type MyBase, the following will yield a compile-time error if T is not derived from MyBase:

#include <boost/type_traits/is_base_of.hpp>
#include <boost/static_assert.hpp>

template<typename T>
class Foo {
BOOST_STATIC_ASSERT_MSG(
(boost::is_base_of<MyBase, T>::value),
"T must be a descendant of MyBase"
);
// Foo implementation as normal
};

If you're using a C++03 compiler with TR1, you can use std::tr1::is_base_of instead of boost::is_base_of; if you're using a C++11 compiler, you can use std::is_base_of instead of boost::is_base_of and the static_assert keyword instead of the BOOST_STATIC_ASSERT_MSG macro:

#include <type_traits>

template<typename T>
class Foo {
static_assert(
std::is_base_of<MyBase, T>::value,
"T must be a descendant of MyBase"
);
// Foo implementation as normal
};

N.b. this will yield true_type for privately and ambiguously-derived types, so this is insufficient if what you really need is to treat T as-a MyBase (in most contexts).

Doc links:

Boost.StaticAssert

Boost.TypeTraits

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).

C++ 11 template sub type

I may not fully understand the question, but it seems if you change

SubTypeImpl SubType;

to

typedef SubTypeImpl SubType;

you can achieve what you want.

C++'s version of ? extends AnotherClass

You can static_assert(std::is_base_of<Base, T>::value, "Argument must extend base!");.

However, note that relative to doing this in Java, in C++ this is nearly totally worthless. There's practically no use case that actually needs it.

C++: How to require that one template type is derived from the other

A trait you want might look like this:

template <typename B, typename D>
struct is_base_of // check if B is a base of D
{
typedef char yes[1];
typedef char no[2];

static yes& test(B*);
static no& test(...);

static D* get(void);

static const bool value = sizeof(test(get()) == sizeof(yes);
};

Then you just need a static assert of some sort:

// really basic
template <bool>
struct static_assert;

template <>
struct static_assert<true> {}; // only true is defined

#define STATIC_ASSERT(x) static_assert<(x)>()

Then put the two together:

template<class R1, class R2>
bool operator==(Manager<R1> m1, Manager<R2> m2)
{
STATIC_ASSERT(is_base_of<R1, R2>::value || is_base_of<R2, R1>::value);

return p1.internal_field == p2.internal_field;
}

If one does not derive from the other, the function will not compile. (Your error will be similar to "static_assert<false> not defined", and it will point to that line.)

How to define a variantx,y,z extracting subtypes of a template parameter

There are two separate tasks:

  1. Extracting the states from the transition-table. This is easily done with pattern-matching.
  2. Removing duplicates. This can be done with O(log n) depth, the complexity comes from std::tuple_cat which uses std::index_sequence, and additionally directly from the latter.

Code for merging type-lists thrown in as a bonus:

#include <tuple>
#include <utility>
#include <type_traits>

namespace detail {
template <template <class...> class TT, template <class...> class UU, class... Us>
auto pack(UU<Us...>)
-> std::tuple<TT<Us>...>;

template <template <class...> class TT, class... Ts>
auto unpack(std::tuple<TT<Ts>...>)
-> TT<Ts...>;

template <std::size_t N, class T>
using TET = std::tuple_element_t<N, T>;

template <std::size_t N, class T, std::size_t... Is>
auto remove_duplicates_pack_first(T, std::index_sequence<Is...>)
-> std::conditional_t<(... || (N > Is && std::is_same_v<TET<N, T>, TET<Is, T>>)), std::tuple<>, std::tuple<TET<N, T>>>;

template <template <class...> class TT, class... Ts, std::size_t... Is>
auto remove_duplicates(std::tuple<TT<Ts>...> t, std::index_sequence<Is...> is)
-> decltype(std::tuple_cat(remove_duplicates_pack_first<Is>(t, is)...));

template <template <class...> class TT, class... Ts>
auto remove_duplicates(TT<Ts...> t)
-> decltype(unpack<TT>(remove_duplicates<TT>(pack<TT>(t), std::make_index_sequence<sizeof...(Ts)>())));
}

template <template <class...> class TT, class... Ts>
using merge_t = decltype(detail::unpack<TT>(std::tuple_cat(detail::pack<TT>(std::declval<Ts>())...)));

template <class T>
using remove_duplicates_t = decltype(detail::remove_duplicates(std::declval<T>()));

Applying it to your transitions-table:

template <template <class...> class TT, class ... Ts>
auto extract_states(TT<Ts...>)
-> TT<typename Ts::entry_state..., typename Ts::next_state...>;

using extracted = decltype(extract_states(std::declval<table>()));
using states = remove_duplicates_t<extracted>;

See it live on coliru.

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.]

Use Boost to ensure template argument inherits from some class

Try with

 BOOST_STATIC_ASSERT(( boost::type_traits::is_base_of< ExceptionBaseClass, T >::value ));

It internally does the same check that @Zolyomi posted in his answer.



Related Topics



Leave a reply



Submit