I am looking for a c++ template which finds the common parent of a set of given classes.
For example
class Animal { ... };
class Mammal : public Animal { ... };
class Fish : public Animal { ... };
class Cat : public Mammal { ... };
class Dog : public Mammal { ... };
std::unique_ptr<common_ancestor_of<Cat,Dog>::type> a = new Cat();
std::unique_ptr<common_ancestor_of<Cat,Dog>::type> b = new Dog();
std::unique_ptr<common_ancestor_of<Cat,Dog>::type> c = new Fish(); // compile error
std::unique_ptr<common_ancestor_of<Cat,Dog,Fish>::type> d = new Fish();
a and b are both std::unique_ptr<Mammal>, c is std::unique_ptr<Animal>.
How is this possible with modern C++?
Afaik no, there is no way in C++ to get the base class of a given class. There is introspection (part of reflection) in the works, but I wouldn't hold my breath for it to go into the standard any time soon.
The only way would be to make the classes cooperate. E.g. Have each class a member alias using Base = Animal. And then cook a trait that finds the common base between them. That would be a lot of work. You need to take into account multiple base classes and chains of inheritance. It's not trivial. You need to analyze your problem and see if all this complicated work is worth it or if there is another simpler way for what you are trying to achieve (which btw you din't mention). You may have an XY problem on your hand.
No, common_ancestor_of would require reflection to get the base class of any of the given classes.
If you have a concrete set of classes, you could use std::variant of all the possible classes.
If not, you could use a base class trait (Either a struct base_class that you specialise for all of your types or a member type like using super = ... or using base = ...) and manually find the common ancestor:
template<typename T>
struct type_identity {
using type = T;
};
template<typename... Types>
struct common_ancestor_of;
template<typename T>
struct common_ancestor_of<T> {
using type = T;
};
template<typename T>
struct common_ancestor_of<T, T> {
using type = T;
};
template<typename T, typename U, typename... Rest>
struct common_ancestor_of<T, U, Rest...> : common_ancestor_of<typename common_ancestor_of<T, U>::type, Rest...> {};
template<typename T, typename U>
struct common_ancestor_of<T, U> {
private:
// Base == Derived, so is in it's inheritance chain
template<typename Base, typename Derived, typename std::enable_if<std::is_same<Base, Derived>::value, int>::type = 0>
static constexpr bool in_inheritance_chain(int) {
return true;
}
// Base != Derived, but Derived has a member type `super`, so recursively check `super`
template<typename Base, typename Derived, typename std::enable_if<!std::is_same<Base, Derived>::value && (noexcept(type_identity<typename Derived::super>{}), true), int>::type = 0>
static constexpr bool in_inheritance_chain(int) {
return in_inheritance_chain<Base, typename Derived::super>(0);
}
// Base != Derived and Derived doesn't have a member type `super`, so it isn't in the inheritance chain
template<typename Base, typename Derived>
static constexpr bool in_inheritance_chain(long) {
return false;
}
// T1 is in the inheritance chain for U1, so it is the common ancestor
template<typename T1, typename U1, typename std::enable_if<in_inheritance_chain<T1, U1>(0), int>::type = 0>
static type_identity<T1> find_common_ancestor(int);
// T1 is not in the inheritance chain, so check T1::super
template<typename T1, typename U1>
static decltype(find_common_ancestor<typename T1::super, U1>(0)) find_common_ancestor(long) {}
public:
using type = typename decltype(find_common_ancestor<T, U>(0))::type;
};
template<typename... Types>
using common_ancestor_of_t = typename common_ancestor_of<Types...>::type;
class Animal { };
class Mammal : public Animal { public: using super = Animal; };
class Fish : public Animal { public: using super = Animal; };
class Cat : public Mammal { public: using super = Mammal; };
class Dog : public Mammal { public: using super = Mammal; };
static_assert(std::is_same<typename Cat::super::super, Animal>::value);
static_assert(std::is_same<common_ancestor_of_t<Cat, Dog>, Mammal>::value);
static_assert(std::is_same<common_ancestor_of_t<Cat, Fish>, Animal>::value);
static_assert(std::is_same<common_ancestor_of_t<Fish, Cat>, Animal>::value);
static_assert(std::is_same<common_ancestor_of_t<Cat, Dog, Fish>, Animal>::value);
This gets the most specialised common ancestor, but consider using the common ancestor you already have: std::unique_ptr<Animal>. If you specifically write std::unique_ptr<common_ancestor_of_t<Cat, Dog>> in your code, it is just as easy to write std::unique_ptr<Mammal>. If it's behind some templated code, std::unique_ptr<Animal> should work just as well.
Related
I'm trying to check if a class that I'm templating is inheriting from another templated class, but I can't find the correct way to do it.
Right now I have the following:
#include <iostream>
template <typename MemberType, typename InterfaceType>
class Combination : public InterfaceType
{
public:
Combination();
virtual ~Combination();
private:
MemberType* pointer;
};
class MyInterface {};
class MyMember {};
class MyCombination : public Combination<MyMember, MyInterface>
{
};
int main()
{
static_assert(std::is_base_of_v<Combination<MyMember, MyInterface>, MyCombination>);
std::cout << "hello";
}
Which is working fine, but in the place this template is placed, I don't have access to the template parameters definitions, and this should be quite generic. What I'd like is to test for the MyCombination class to inherit from a generic Combination without taking into account the template arguments, something like this:
static_assert(std::is_base_of_v<Combination, MyCombination>);
or
static_assert(std::is_base_of_v<Combination<whatever, whatever>, MyCombination>);
Would you know how to check for this?
In this case I can't use boost libraries or other external libraries.
Thanks!
EDIT: I don't have access to modify the Combination class, and what I can change is the assert and the My* classes.
This can easily be done with the C++20 concepts. Note that it requires a derived class to have exactly one public instantiated base class.
template <typename, typename InterfaceType>
class Combination : public InterfaceType {};
class MyInterface {};
class MyMember {};
class MyCombination : public Combination<MyMember, MyInterface> {};
template<class Derived, template<class...> class Base>
concept derived_from_template = requires (Derived& d) {
[]<typename... Ts>(Base<Ts...>&) {}(d);
};
static_assert(derived_from_template<MyCombination, Combination>);
Demo
The equivalent C++17 alternative would be
#include <type_traits>
template<template<class...> class Base, typename... Ts>
void test(Base<Ts...>&);
template<template<class...> class, class, class = void>
constexpr bool is_template_base_of = false;
template<template<class...> class Base, class Derived>
constexpr bool is_template_base_of<Base, Derived,
std::void_t<decltype(test<Base>(std::declval<Derived&>()))>> = true;
static_assert(is_template_base_of<Combination, MyCombination>);
The derived class hides the name of an overload set from the base class if the derived class has the same name defined, but we can always introduce that overload set back with using-declaration:
template <class BASE>
class A : public BASE
{
public:
using BASE::some_method;
void some_method();
}
But what if I introduce all overload sets from variadic base classes?
Would I be able to write something like this?
template <class... BASES>
class A : public BASES...
{
public:
using BASES::some_method...;
void some_method();
}
I've considered using a helper class like:
template <class... BASES>
struct helper;
template <>
struct helper<> {};
template <class OnlyBase>
struct helper<OnlyBase> : OnlyBase
{
using OnlyBase::some_method;
};
template <class Base1, class... OtherBases>
struct helper<Base1, OtherBases> : public Base1, public helper<OtherBases...>
{
using Base1::some_method;
using helper<OtherBases...>::some_method;
};
And it does work. But it requires a lot of typing (of course I can use macro but I try to use c++'s compile-time feature whenever possible), and when I want to introduce more methods, i have to change much in that piece of code.
A perfect answer would be a simple syntax, but if there's none, I will go with the helper class.
Here is a trick how to reduce handwriting:
// U<X,Y> is a binary operation on two classes
template<template<class,class>class U, class... Xs> struct foldr;
template<template<class,class>class U, class X> struct foldr<U,X> : X {};
template<template<class,class>class U, class X, class... Xs> struct foldr<U,X,Xs...> : U<X, foldr<U,Xs...>> {};
// our operation inherits from both classes and declares using the member f of them
template<class X, class Y> struct using_f : X,Y { using X::f; using Y::f; };
struct A { void f(int) {} };
struct B { void f(char) {} };
struct C { void f(long) {} };
struct D : foldr<using_f, A, B, C> {};
int main() {
D d;
d.f(1);
d.f('1');
d.f(1L);
return 0;
}
So we should write foldr once, then write simple ad-hoc operations - using_f, using_g, using_f_g
Maybe there is a way to further simplifying. Let me think a bit...
I asked the following question in this post (pasted below for convenience). One of the comments suggested that there is a CRTP-based solution to the problem. I am not able to figure out how CRTP is relevant here (well, I never used CRTP before, so I am not used to thinking in these terms). So, how would a CRTP-based solution look like?
Here is the cited question:
Is it possible to write a template function that would possess type information about the base class of the template argument? (assuming that the template argument derives from one class only)
So, I am looking for something like this:
template <class T>
auto f(T t) -> decltype(...) { // ... is some SFINAE magic that
// catches B, the base of T
std::cout << (B)t << std::endl;
}
Some relevant background: I am writing a generic implementation of the A* algorithm. The template argument is a Node structure. So, the user might define:
struct NodeBase {
REFLECTABLE((double)g, (double)f)
// Using the REFLECTABLE macro as described here:
// https://stackoverflow.com/a/11744832/2725810
};
struct NodeData : public NodeBase {
using Base1 = NodeBase;
REFLECTABLE((double)F)
};
I would like to write a function that prints the contents of the node structure. REFLECTABLE does all the hard work of extracting the fields of the struct. However, when the user gives me a NodeData instance, my function needs to print the contents of the NodeBase component as well. I would like to later add overloads of my function for two and three base classes.
to know whether a class derives from a base class we have the std::is_base_of<> template structure, which can be used in conjunction with partial specialisation, or std::enable_if.
Here is a demonstration of using a partially specialised structure to apply a an operation depending on whether it's derived from node_base or not (in this case, it just prints the base object but you could do any other operation)
#include <iostream>
#include <type_traits>
// base class
struct node_base
{
};
std::ostream& operator<<(std::ostream& os, const node_base& nb)
{
os << "node_base_stuff";
return os;
}
// a class derived from node_base
struct node : public node_base
{
};
// a class not derived from node_base
struct not_node
{
};
// apply the general case - do nothing
template<class T, class = void>
struct report_impl
{
static void apply(const T&) {};
};
// apply the case where an object T is derived from node_base
template<class T>
struct report_impl<T, std::enable_if_t< std::is_base_of<node_base, T>::value > >
{
static void apply(const T& t) {
std::cout << static_cast<const node_base&>(t) << std::endl;
};
};
// the general form of the report function defers to the partially
// specialised application class
template<class T>
void report(const T& t)
{
report_impl<T>::apply(t);
}
using namespace std;
// a quick test
auto main() -> int
{
node n;
not_node nn;
report(n);
report(nn);
return 0;
}
expected output:
node_base_stuff
Here is my own first solution. It is not CRTP though and it suffers from a huge drawback as explained at the end of the answer:
template <class Base1_ = void, class Base2_ = void, class Base3_ = void,
class Base4_ = void>
struct ManagedNode;
// For classes that do not derive
template <> struct ManagedNode<void, void, void, void> {
using Base1 = void; using Base2 = void; using Base3 = void;
using Base4 = void;
};
// To avoid inaccessible base
// See http://stackoverflow.com/q/34255802/2725810
struct Inter0: public ManagedNode<>{};
// For classes that derive from a single base class
template <class Base1_>
struct ManagedNode<Base1_, void, void, void> : public Inter0,
public Base1_ {
using Base1 = Base1_;
};
// To avoid inaccessible base
template <class Base1_>
struct Inter1: public ManagedNode<Base1_>{};
// For classes that derive from two base classes
template <class Base1_, class Base2_>
struct ManagedNode<Base1_, Base2_, void, void> : public Inter1<Base1_>,
public Base2_ {
using Base2 = Base2_;
};
// Some user classes for testing the concept
struct A : public ManagedNode<> {
int data1;
};
struct B : public ManagedNode<> {};
struct C : public ManagedNode<A, B> {};
int main() {
C c;
std::cout << sizeof(c) << std::endl;
return 0;
}
This code produces the output of 12, which means that c contains the data1 member three times! For my purposes this drawback over-weighs the benefits of the reflection that this approach provides. So, does anyone have a suggestion for a better approach?
Consider
class B; class C;
class A {
using linked_from = std::tuple<B,C>; // i.e. A is "linked from" B and C.
};
class B {
using linked_to = std::tuple<A,C>; // i.e. B is "linked to" A and C.
};
class C {
using linked_to = std::tuple<A>;
using linked_from = std::tuple<B>;
};
What I want to do is redesign the above so that there is no maintenance responsibilities whenever the linked_to member types are changed. Perhaps something along the lines of
template <typename To, typename From>
struct LinkFromMap {
using linked_from = From;
};
template <typename From, typename To>
struct LinkPair : LinkFromMap<To, From> {};
template <typename T, typename... Ts>
struct Link : LinkPair<Ts, T>... {
using linked_to = std::tuple<Ts...>;
};
class B; class C;
class A {};
class B : public Link<B, A,C> {};
class C : public Link<C, A> {};
int main() {
static_assert(std::is_same<B::linked_to, std::tuple<A,C>>::value, "");
// Still need to obtain std::tuple<B,C> from A, std::tuple<B> from C, etc...
}
A and C do not need to keep their linked_from member types, as long as std::tuple<B,C> can be obtained from A and std::tuple<B> can be obtained from C. That is why I've defined LinkFromMap above, but I can't figure out how to use LinkFromMap to achieve that. Can it be used at the end somehow to form the packs <A, B,C> and <C,B> or something like that? Or is there a better way to automate type retrievals that linked_from was designed for?
The derived class hides the name of an overload set from the base class if the derived class has the same name defined, but we can always introduce that overload set back with using-declaration:
template <class BASE>
class A : public BASE
{
public:
using BASE::some_method;
void some_method();
}
But what if I introduce all overload sets from variadic base classes?
Would I be able to write something like this?
template <class... BASES>
class A : public BASES...
{
public:
using BASES::some_method...;
void some_method();
}
I've considered using a helper class like:
template <class... BASES>
struct helper;
template <>
struct helper<> {};
template <class OnlyBase>
struct helper<OnlyBase> : OnlyBase
{
using OnlyBase::some_method;
};
template <class Base1, class... OtherBases>
struct helper<Base1, OtherBases> : public Base1, public helper<OtherBases...>
{
using Base1::some_method;
using helper<OtherBases...>::some_method;
};
And it does work. But it requires a lot of typing (of course I can use macro but I try to use c++'s compile-time feature whenever possible), and when I want to introduce more methods, i have to change much in that piece of code.
A perfect answer would be a simple syntax, but if there's none, I will go with the helper class.
Here is a trick how to reduce handwriting:
// U<X,Y> is a binary operation on two classes
template<template<class,class>class U, class... Xs> struct foldr;
template<template<class,class>class U, class X> struct foldr<U,X> : X {};
template<template<class,class>class U, class X, class... Xs> struct foldr<U,X,Xs...> : U<X, foldr<U,Xs...>> {};
// our operation inherits from both classes and declares using the member f of them
template<class X, class Y> struct using_f : X,Y { using X::f; using Y::f; };
struct A { void f(int) {} };
struct B { void f(char) {} };
struct C { void f(long) {} };
struct D : foldr<using_f, A, B, C> {};
int main() {
D d;
d.f(1);
d.f('1');
d.f(1L);
return 0;
}
So we should write foldr once, then write simple ad-hoc operations - using_f, using_g, using_f_g
Maybe there is a way to further simplifying. Let me think a bit...