С С++ 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 какой-либо базовый класс, мое решение снова будет работать.
Ответы
Ответ 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/тривиальным/агрегированным, существуют некоторые типы признаков, которые могут вам помочь: