С C++17 Можно ли определить, имеет ли структура/класс какую-либо базу?

мне нужен признак типа, который будет true, если данный тип происходит от чего-либо, и false в противном случае.

например:

template<class T>
struct is_inherit
    //... logic of inheritance detection
    ;

template<class T>
void AppLogic(){
    if constexpr(is_inherit<T>::value) {
        puts("T has base");
        //...
    } else {
        puts("T doesn't have base");
        //...
    }
}

struct A {};
struct C {};
struct B: C {};

int main() {
    AppLogic<A>(); // print: T doesn't have base 
    AppLogic<B>(); // print: T has base
}

возможно ли как-то реализовать эту структуру признака "is_inherit"?


почему?

Я разрабатываю ручной конструктор кадров стека для Windows x64. Согласно https://docs.microsoft.com/en-us/cpp/build/return-values-cpp документация, если тип:

  • есть длину 1, 2, 4, 8, 16, 32, или 64 бит;
  • не имеет определяемого пользователем конструктора, деструктора или оператора назначения копирования;
  • не private или protected нестатических членов данных;
  • не имеет нестатических элементов данных ссылочного типа;
  • не имеет базовых классов;
  • не имеет виртуальных функций;
  • и не имеет членов данных, которые также не отвечают этим требованиям;

тогда его возвращаемое значение находится в регистр RAX, в противном случае функция есть скрытый аргумент, который я должен обнаружить и обработать.

это было определение модуля C++03, однако в C++11 это изменилось:

поскольку определение изменилось в стандарте C++11, мы не рекомендуем использовать std::is_pod для этого теста.

до сих пор с некоторыми сопряженными признаками я мог обнаружить, соответствует ли тип определению C++03 POD или нет. Однако с C++17 агрегат правила изменились, и это нарушило мое решение.

Если я каким-то образом смогу определить, имеет ли тип T какой-либо базовый класс, мое решение будет работать снова.

2 ответов


Да, это возможно, по крайней мере для агрегатов.

Сначала мы строим шаблон класса, который преобразуется в любую правильную базу его параметра шаблона:

template<class T>
struct any_base {
    operator T() = delete;
    template<class U, class = std::enable_if_t<std::is_base_of_v<U, T>>> operator U();
};

затем мы определяем, является ли параметр шаблона T является агрегатной конструктивной из значения типа any_base<T>:

template<class, class = void> struct has_any_base : std::false_type {};
template<class T>
struct has_any_base<T, std::void_t<decltype(T{any_base<T>{}})>> : std::true_type {};

пример.


Я считаю, что проверки, если "T происходит от чего-либо " невозможно, по крайней мере, не стандартным образом. Если вы используете этот метод, чтобы проверить, является ли тип POD / trivial / aggregate, есть некоторые черты типа, которые могут вам помочь: