С 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, есть некоторые черты типа, которые могут вам помочь: