C++: How to Require That One Template Type Is Derived from the Other

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

Make sure that typename type is a Derived of Base

You may use static_assert and std::is_base_of.

#include <type_traits>

struct B {};

template <typename T>
class C {
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
};

struct D : public B {};
struct KO {};

template class C<B>;
template class C<D>;
template class C<KO>;

int main()
{
}

main.cpp: In instantiation of 'class C<KO>':
main.cpp:16:16: required from here
main.cpp:7:5: error: static assertion failed: T should inherit from B
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
^
======= clang =======
main.cpp:7:5: error: static_assert failed "T should inherit from B"
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:16:16: note: in instantiation of template class 'C<KO>' requested here
template class C<KO>;
^

Online Demo

C++ Concepts: Checking if derived from a templated class with unknown template parameter

If you want to check for specialisations of A specifically, that isn't too difficult.

template <class C>
concept A_ = requires(C c) {
// IILE, that only binds to A<...> specialisations
// Including classes derived from them
[]<typename X>(A<X>&){}(c);
};

The lambda is basically just a shorthand for a function that is overloaded to accept A specialisations. Classes derived from such specialisations also count towards it. We invoke the lambda with an argument of the type we are checking... and the constraint is either true or false depending on whether the call is valid (the argument is accepted).

Then, just plug it in:

template <A_ T>
class B{};

Here it is working live.

How to elegantly check if the template type is derived from the specific base class in C++11?

Use std::enable_if_t (equivalent to std::enable_if<B,T>::type) and std::is_base_of.

#include <type_traits>

template <typename T,
typename = std::enable_if_t<std::is_base_of<Base, T>::value> >
class Context {
public:
void run() {
t.run();
};
private:
T t;
};

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

Can C++20 concept be used to avoid hiding template function from base class?

This is specified in namespace.udecl#14, emphasis mine,

When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list ([dcl.fct]), trailing requires-clause (if any), cv-qualification, and ref-qualifier (if any), in a base class (rather than conflicting). Such hidden or overridden declarations are excluded from the set of declarations introduced by the using-declarator.

As to your questions,

  • [X]&[Y] has the same name AND parameter list.
  • But qualification of [X] and [Y] are difference.
  • Thus, no hides or overrides occur.

Yes, [X] and [Y] are exactally the same except for the trailing requires clause. So, no hides occur.



Related Topics



Leave a reply



Submit