Given a list of classes, I need to find the inheritance relationships between the classes. For example:
class Animal {};
class Dog : public Animal {};
class Bulldog : public Dog {};
class Cat : public Animal {};
using boost::mp11::mp_list;
template<typename... Class>
using class_bases = ...; // a mp_list of mp_list<Derived, Base>, with void meaning no base
static_assert(
std::is_same_v<
class_bases<Animal, Dog, Bulldog, Cat>,
mp_list<
mp_list<Animal, void>,
mp_list<Dog, Animal>,
mp_list<Bulldog, Dog>,
mp_list<Cat, Animal>
>
>);
I have a solution that works well for single inheritance hierarchies. It is O(n) and it does not use recursion:
template<typename Derived, typename Class>
struct direct_base_impl {
static Class select(Class*);
};
template<typename Derived>
struct direct_base_impl<Derived, Derived> {
static void select(...);
};
template<typename Derived, typename... Class>
struct direct_base : direct_base_impl<Derived, Class>... {
using direct_base_impl<Derived, Class>::select...;
using type = decltype(select(std::declval<Derived*>()));
};
static_assert(
std::is_same_v<
direct_base<Bulldog, Animal, Dog, Bulldog>::type,
Dog
>);
template<typename... Class>
using class_bases = mp_list<
mp_list<
Class,
typename direct_base<Class, Class...>::type
>...
>;
Unfortunately this approach won't work in presence of multiple inheritance.
I have coded a solution that uses brute force. It works, except for classes that inherit the same base both directly and indirectly. I don't care about this case, because, in my context (yomm2 open multi-methods library), it doesn't make sense anyway. More annoying, that solution has a O(n^3) worst case "performance", in presence of MI.
Does anybody know of a solution to this problem, or has ideas?
There are some additional SFINAE-based gesticulations for dealing with multiple inheritance, in this situations.
Fortunately, you don't need to do them yourself, because std::is_base_of has already done them for you:
std::is_base_of<A, B>::value is true even if A is a private, protected,
or ambiguous base class of B.
Emphasis mine. Simply reimplement your template to use std::is_base_of or std::is_base_of_v and it'll deal with multiple inheritance on your behalf.
Related
Compiling the following contrived example:
class Base
{};
class Derived : public Base
{};
template< typename T >
class A
{};
class B
{
public:
static void f( const A< Base >& ) {}
};
int main()
{
A< Base > tb;
A< Derived > td;
B::f( tb );
B::f( td );
return 0;
}
using g++-8 gives me the following error:
error: no matching function for call to 'B::f(A<Derived>&)'
B::f( td );
note: no known conversion for argument 1 from 'A<Derived>' to 'const A<Base>&'
Why?
Since Derived is-a Base and it doesn't override any of Base's stuff, why can't I give a Derived in the place of a Base in the templated function parameter?
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...
Template instances, like A<Base> and A<Derived>, are different types. In particular they do not have any inheritance relationship even if Base and Derived do.
There are quite a few ways you can make what you want work.
First, you could make A<Derived> explicitly derive from A<Base>, but that means adding a whole class definition.
template<>
class A<Derived> : public A<Base>
{};
Second, you can provide an implicit conversion from A<Derived> to A<Base> in the form of a constructor template. You can use std::enable_if and std::is_base_of to only allow A<T> where T is derived from Base, or directly std::is_same if you only want to consider this particular Derived type.
template<typename T>
class A
{
template<typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
A(A<U> const& other);
};
Third, you can provide an implicit conversion in the form of an operator template, in much the same way.
template<typename T>
class A
{
template<typename U, typename = std::enable_if_t<std::is_base_of_v<U, T>>>
operator U();
};
Fourth, you can make f a function template and restrict what types it takes.
template<typename T, typename = std::enable_if_t<std::is_base_of_v<Base, T>>>
static void f(A<T> const& a);
I want to achive the following behavior.
In a base class I wish to have a container to store pointers to methods of derived class. (I want to store there h1 and h2).
Base class is also implementing methods allowing to store those pointers and the container itself
There is not any code ready yet, cause I wonder whether it's possible at all - eg:
template<typename E, typename S>
using Map = std::unordered_map<E, std::function<S* (S&, void)>>;
template<typename E, typename S>
class Base {
someFunctToPutPointersIntoMap() {}
Map<E, S> mEventMap;
}
template<typename E, typename S>
class Derived: public Base<E, S> {
public:
Derived* h1(void) {};
Derived* h2(void) {};
};
However how then I can declare object of derived class? For me its parameters are recursive eg.
Derived<E, Derived<E, Derived<E, Derived<E, ...etc... > object;
So it will never compile. I am sure there is some way to handle it, however I have none idea.
Is it possible to derive all template instantiations that have a derived class as their argument from the instantiation that has the base class as its argument?
In code:
class Base{};
class Derived1 : Base{};
class Derived2 : Base{};
template<typename T>
class Templ /*: Templ<Base> if T derives from Base*/
{};
How would one do that?
Make a specialization for Templ<Base>, and then use SFINAE along with std::is_base_of to derive a separate specialization from Templ<Base>.
template<typename T, typename V = void>
class Templ
{};
template<>
class Templ<Base>
{};
template<bool B, typename R = void>
using enable_if_t = typename std::enable_if<B, R>::type;
template<typename T>
class Templ<T, enable_if_t<std::is_base_of<Base, T>::value>>
: public Templ<Base>
{};
It depends what exactly you want to do. If you want this to work only for some specific, known baseclass, it can easily accomplished, e.g. like in 0x499602D2's answer.
However the way I interpret your question you want to have a template which derives from the instantiation for it's arguments baseclass, whichever that might be. This is not possible in standard c++ (yet), since there is no way to query what class a specific type is derived from, only if it is derived from a specific classes. For more on this (and possible future solutions look at this question.
Suppose I have a derived class Derived. As well as taking template parameters, Derived is a derived class of Base, which in turn is templated on Derived.
The following illustrates an example of a working solution:
template <int i, typename T>
class Derived : public Base<Derived<i,T>>
{
};
template <typename DerivedType>
class Base
{
};
When the template argument list of Derived gets large, however, this becomes a pain, because coders who want to add derived classes to the library have to write the template arguments twice. Is there anyway of somehow automating this?
Here's what I'm after (the following doesn't compile because this doesn't exist yet, but it illustrates what I'm looking for):
template <int i, typename T>
class Derived : public Base<decltype(*this)>
{
};
template <typename DerivedType>
class Base
{
};
I'm open to an elegant macro solution (oxymoron perhaps?) if there is no way of achieving this with templates.
Use a traits class to contain the metadata rather than passing each item in the parameter list.
Here's what I do in a library I'm writing, soon to be open sourced.
First, there's the default traits class to cover the common case. I want to handle a range of common cases so it's also a template, but otherwise it could be a regular class. The parameterization is only what's convenient to the user, not the final detailed implementation parameterization, which instead comprises its contents.
template< typename rep_type, unsigned mantissa_values, rep_type fractional_cycles >
struct positive_logarithm_default_traits {
typedef double conv_basis;
static constexpr bool range_check = true;
typedef rep_type rep;
protected:
static constexpr rep max_rep = std::numeric_limits< rep >::max();
static constexpr rep unity_rep = mantissa_values * fractional_cycles;
// Another specialization could overflow to INFINITY and underflow to 0.
[[noreturn]] static rep underflow() { throw range_error( false ); }
[[noreturn]] static rep overflow() { throw range_error( true ); }
};
Then I define a metafunction to transform one instance of the class to another. It works within the traits class space, which can help compile time by eliminating instantiation of intermediate results if multiple metaprocessing transformations are strung together.
// The traits of a logarithm which represents the inverse of another logarithm.
template< typename traits >
struct inverse_traits : traits {
static constexpr decltype( traits::unity_rep ) unity_rep
= traits::max_rep - traits::unity_rep;
};
Although the traits class usually only contains compile-time data, I'll allow for runtime variation by inheriting from it. In such cases, the traits class may also want to access the state of the derived class. That's essentially CRTP. But, a given traits class might want to service several final derived classes with non-traits parameterization. So I make an additional class with runtime state accessible to the traits class, by static_cast< logarithm_state_base< traits > >( * this ) — this is functionally equivalent to CRTP but sidesteps a lot of metaprogramming complexity.
template< typename traits >
class logarithm_state_base : public traits {
protected:
typename traits::rep log_value;
};
Finally, the derived class provides the same convenient interface to the user as the default traits class interprets. Internally, though, it references all metadata through members inherited from the traits class.
If the user defines their own traits class, then the template parameters before typename traits_type (except mantissa_values) are vestigial and unused. An alias template could set them all to void to provide a solely traits-based user interface. Alternately, if I anticipated that traits usage would be more popular, I could do it the other way and let traits be the "native" interface and the itemized parameters be the convenience alias.
template<
typename rep, // Underlying representation type
unsigned mantissa_values, // # distinct values per power of 2
rep fractional_cycles = std::numeric_limits< rep >::max() / ( mantissa_values * 2 ) + 1,
typename traits_type = positive_logarithm_default_traits< rep, mantissa_values, fractional_cycles >
>
class static_positive_logarithm
: public logarithm_state_base< traits_type > {
static_assert ( std::is_unsigned< typename traits_type::rep >::value,
"Representation type must be unsigned." );
…
template <int i, typename X>
struct Derived
{
class T : public Base<T> { ... };
};
Derived<2, char>::T x;
I have an inheritance chain of CRTP classes. The CRTP classes derive from each other, until a 'final' derived class passes itself as the CRTP parameter and finalizes the inheritance chain.
template <class W>
struct Base
{
.....
};
template <class W>
struct Derived_inheritable: public Base<W>
{
....
}
template <class W>
struct Derived2_inheritable: public Derived_inheritable<W>
{
....
}
...
What I want to do is to be able to have such 'final' end-user classes at each level of the CRTP inheritance chain, that involve no templates:
typedef Derived1_inheritable<Derived1> Derived1;
As you can guess, this typedef does not work, because it references its own type being defined. The question is how to achieve this?
The way I could think of, is:
struct Derived1: public Derived1_inheritable<Derived1>
{
//not convenient, need to redefine at least a forwarding constructor
}
As the comment in the code says, this is not a very elegant solution - I need to redefine the constructor to forward to the base constructor. Does anyone know a more elegant way?
typedef Derived1_inheritable Derived1;
That line makes no sense, the argument to the template is a type but you are trying to pass a template (incidentally the same template that you are instantiating, but besides that extra quirk the fact is that your template takes a type as argument and you are passing a non-type)
It is not really clear from the question what you are trying to achieve. You should work on stating your goal rather than your approach to solving that goal.
I want to make a "final" class for each DerivedX_inheritable that is non-template and passes itself as the W parameter.
That is exactly done in the code that you produded:
struct Derived1: public Derived1_inheritable<Derived1> {}
which is a type definition (make a "final" class). The fact that your CRTP bases require arguments that must be provided by the end user and the need of the forwarding constructor thereof is just a side effect of your design.
I think I found an elegant solution:
template <class W>
struct Base
{
.....
};
template <class W>
struct Derived_inheritable: public Base<W>
{
....
}
//solution
struct Derived2_dummy;
template <class W=derived2d_ummy>
struct Derived2_inheritable: public Derived_inheritable<W>
{
....
}
struct derived2_dummy: public: Derived_inheritable<>{};
typedef Derived2_inheritable<> Derived2;