Подтвердить что ты не робот

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

Мне нужна черта типа, которая будет истинна, если данный тип получен из чего-либо, а 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 бит;
  • не имеет определенного пользователем конструктора, деструктора или оператора присваивания копии;
  • не имеет частных или защищенных нестатических элементов данных;
  • не имеет нестатических элементов данных ссылочного типа;
  • не имеет базовых классов;
  • не имеет виртуальных функций;
  • и не имеет данных, которые также не отвечают этим требованиям;

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Пример.

Ответ 2

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