4

C++ has is_base_of<Base,Derived>. However, this also includes “grandparent” types.

Is there a way to get have is_child_of<Parent,Child> functionality? The purpose is to use types as sentinel 'interface' markers in an SFINAE context, without being affected by sentinels that may or may not be added to parent types.

That is, the following output is expected to be "true, false". (The output with is_base_of is "true, true".)

#include <iostream>
#include <type_traits>

class A {};

class B : A {};

class C : B {};

int main() 
{
    std::cout << std::boolalpha;
    std::cout << "a2b: " << std::is_child_of<A, B>::value << '\n';
    std::cout << "a2c: " << std::is_child_of<A, C>::value << '\n';
}
user2864740
  • 54,112
  • 10
  • 112
  • 187

1 Answers1

1

C++ doesn't have reflection, child's storage contain's parent's storage and it's hard to draw a line between one subobject and another. Some metaprogramming must be dome, mimicking libraries similar to Qt or MFC\WFC

#include <iostream>
#include <type_traits> 

#define DECLARE_CLASS(Name,  ParentName)  using Parent = ParentName;
#define PARENT_CLASS(Name) Name::Parent

class LibBase {
public:
     DECLARE_CLASS(LibBase,  void)
};

class A : public LibBase {
public:
    DECLARE_CLASS(A,  LibBase)
};

class B : public A {
public:
    DECLARE_CLASS(B,  A)
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_same<PARENT_CLASS(B), A>::value << std::endl;
    std::cout << std::is_same<PARENT_CLASS(B), LibBase>::value << std::endl;
}

Clearly this simple approach have pitfall that we don't get an error if class is not defined using our macro., and it is static only,

First issue can worked around by creating a "trait" nested class by declaration, which got name based on class name passed to DECLARE_OBJECT. This would make result of PARENT_CLASS(Name) unique, e.g.

#define DECLARE_CLASS(Name,  ParentName)  struct TraitsOf##Name { \
    using Parent = ParentName; \
};

#define PARENT_CLASS(Name) Name::TraitsOf##Name::Parent

Second issue can be worked around by creating own RTTI function within macro-definition

Sadly form is_child_of<LibBase, A>::value is unattainable with this because macro substitution happens before template substitution. Perhaps some static registering approach can be used to give classes unique traits in wait how BOOST_TYPEOF does but getting rid of macrodefinitions in user code would be nigh-impossible.

Swift - Friday Pie
  • 8,633
  • 1
  • 16
  • 31