How to Test Whether Class B Is Derived from Template Family of Classes

Trait to check if some specialization of template class is base class of specific class

If you can assume that a derived type uses a public inheritance from B<Args...> (and so the upcasting is possible), then you can use the following SFINAE:

namespace detail
{
template <typename Derived>
struct is_derived_from_B
{
using U = typename std::remove_cv<
typename std::remove_reference<Derived>::type
>::type;

template <typename... Args>
static auto test(B<Args...>*)
-> typename std::integral_constant<bool
, !std::is_same<U, B<Args...>>::value>;

static std::false_type test(void*);

using type = decltype(test(std::declval<U*>()));
};
}

template <typename Derived>
using is_derived_from_B = typename detail::is_derived_from_B<Derived>::type;

Tests:

static_assert(is_derived_from_B<const D<int, char, float>>::value, "!");
static_assert(!is_derived_from_B<int>::value, "!");
static_assert(!is_derived_from_B<B<int,int>>::value, "!");
static_assert(!is_derived_from_B<std::vector<int>>::value, "!");

DEMO 1

It can be generalized to accept any base class template:

namespace detail
{
template <template <typename...> class Base, typename Derived>
struct is_derived_from_template
{
using U = typename std::remove_cv<
typename std::remove_reference<Derived>::type
>::type;

template <typename... Args>
static auto test(Base<Args...>*)
-> typename std::integral_constant<bool
, !std::is_same<U, Base<Args...>>::value>;

static std::false_type test(void*);

using type = decltype(test(std::declval<U*>()));
};
}

template <template <typename...> class Base, typename Derived>
using is_derived_from_template
= typename detail::is_derived_from_template<Base, Derived>::type;

Tests:

static_assert(is_derived_from_template<B, const D<int, int>>::value, "!");
static_assert(!is_derived_from_template<B, int>::value, "!");
static_assert(!is_derived_from_template<B, B<int, int>>::value, "!");
static_assert(!is_derived_from_template<B, std::vector<int>>::value, "!");

DEMO 2

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++ member function template in derived class, how to call it from base class?

You could use the vistor pattern for this:

class IVisitor
{
public:
virtual void on_data( double, const char * )=0;
virtual void on_data( std::string, const char * )=0;
};

class Base
{
public:
virtual void visit( IVisitor * v )=0;
};

class X : public Base
{
private:
double m_double;
std::string m_string;
public:
void visit( IVisitor * v)
{
v->on_data( m_double, "m_double" );
v->on_data( m_string, "m_string" );
}
};

Base * base = ...;
XmlArchive ar; // This must derive from IVisitor
base->visit(&ar);
ParameterList pl; // This must derive from IVisitor
base->visit(pl);

If you dislike the need to implement each of the different on_data types in the IVisitor, you can use a boost::any - but in my experience the branching required in the implementations of that function are not worth it.

Create a family of template classes convertible to each other

Shorter reproduction:

struct B { };
struct D : B { using B::B; };
struct E : B { using B::B; };

E e{D{}}; // error

Basically, copy and move constructors are never inherited - those are specifically excluded from consideration as candidates. You'd have to explicitly add those extra candidates if you want them.

From [over.match.funcs]/8:

A constructor inherited from class type C ([class.inhctor.init]) that has a first parameter of type “reference to cv1 P” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type cv2 D if the argument list has exactly one argument and C is reference-related to P and P is reference-related to D. [ Example:

struct A {
A();
A(A &&); // #1
template<typename T> A(T &&); // #2
};
struct B : A {
using A::A;
B(const B &); // #3
B(B &&) = default; // #4, implicitly deleted

struct X { X(X &&) = delete; } x;
};
extern B b1;
B b2 = static_cast<B&&>(b1); // calls #3: #1, #2, and #4 are not viable
struct C { operator B&&(); };
B b3 = C(); // calls #3

— end example ]


This is CWG 2356 and also CWG 1959 (which was also partially resolved by P0136).

c++ function cannot derive template for child class of base class with templates

(using bitset = boost::dynamic_bitset)

Your bitstring_individual is not the same as individual<bitset, bitset>, and the compiler rightfully does not recognize them as such. One inherits the other, yes, but that does not make them interchangeable everywhere - in particular when used as template arguments.

In short: vectors (and other containers) of different (even polymorphically related) types are not covariant. Just like you cannot pass a std::vector<int> to a function expecting a std::vector<long> you cannot pass a std::vector<bitstring_individual> where a std::vector<individual<bitset, bitset>> is expected.

Note: Yes, they are different conversions, but the idea is the same.

Imagine that sizeof(individual<bitset, bitset>) = 32 and that bitstring_individual adds some members so that sizeof(bitstring_individual) = 48. If the compiler deduced T = S = bitset, then it would generate a method signature containing std::vector<individual<bitset, bitset>>, so a vector whose elements have size 32. But when you try to call it, you are passing a vector whose elements have size 48. Those vectors are not covariant, which would invariably lead to problems.

If you want your concrete individuals to have no other functionality than what the templated base class provides, just do this:

using bitstring_individual = individual<bitset, bitset>;

Otherwise, your vectors cannot store the individuals directly - you would have to use something like std::vector<std::shared_ptr<individual<T, S>>> (alternatively unique_ptr or ref instead of shared_ptr) for all population vectors.

Check at compile-time if an uninstantiated class template inherits from its first template parameter

However, I think that implementing template_parameter_is_base_of should be possible because a compiler should know at compile-time whether a template class inherits from its template parameter or not.

A template is essentially a parameterized tool for manufacturing certain C++ constructs: class, function, or variable. A template, in and of itself, is not yet the thing it will make. A class template does not inherit from anything because it is not a class yet. So the question itself is not a functional one.

Coupled with that is the fact that explicit/partial template specialization exists. Even if the base class template did indeed inherit from its first template parameter, that's no guarantee of anything. You still have no idea if any particular WithParent<T> instantiation of the template will actually use the base template. A user could easily specialize WithParent for a particular type, or even employ partial specialization for a whole family of types.

What you want is not a thing C++ can support. If you're trying to verify something or prevent certain misuse or whatever, you're going to have to do it another way.



Related Topics



Leave a reply



Submit