Проверьте, является ли тип ПРЯМОМ производным от (является потомком) другого типа в контексте «enable if» - PullRequest
4 голосов
/ 08 февраля 2020

C ++ имеет is_base_of<Base,Derived>. Тем не менее, это также включает «дедушкины» типы.

Есть ли способ получить функциональность is_child_of<Parent,Child>? Цель состоит в том, чтобы использовать типы в качестве маркеров 'интерфейса' дозорного в контексте SFINAE, без влияния дозорных, которые могут или не могут быть добавлены к родительским типам.

То есть следующее ожидается, что вывод будет "true, false". (Вывод с is_base_of равен «истина, истина».)

#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';
}

1 Ответ

1 голос
/ 09 февраля 2020

C ++ не имеет отражения, дочернее хранилище содержит хранилище родителя, и трудно провести линию между одним подобъектом и другим. Некоторые метапрограммирования должны быть купольными, имитируя библиотеки, подобные Qt или MFC \ WF C

#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;
}

Очевидно, что у этого простого подхода есть ловушка, в которой мы не получим ошибку, если класс не определен с помощью нашего макроса. и это только stati c,

Первая проблема может быть решена путем создания вложенного класса «trait» по объявлению, который получил имя на основе имени класса, переданного в DECLARE_OBJECT. Это сделало бы результат PARENT_CLASS (Name) уникальным, например,

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

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

Вторая проблема может быть решена путем создания собственной функции RTTI в макроопределении

К сожалению, форма is_child_of<LibBase, A>::value недостижима при это потому, что замена макроса происходит перед заменой шаблона. Возможно, какой-либо подход регистрации * stati c может быть использован для того, чтобы дать классам уникальные черты в ожидании, как это делает BOOST_TYPEOF, но избавиться от макроопределений в пользовательском коде было бы почти невозможно.

...