是否可以在类层次结构中获取基类类型?
例如:
struct A{};
struct B{} : public A;
struct C{} : public B;
我想要一些这样的模板typedef Base<T>::Type
:
Base<A>::Type == A
Base<B>::Type == A
Base<C>::Type == A
这可能吗?如果我有多重继承怎么办?
C++ 中的类可以有多个基类,因此具有“get me the base”特性是没有意义的。
但是,TR2 添加的内容包括新的编译器支持的特征std::tr2::bases
和std::tr2::direct_bases
,它返回基类的不透明类型列表。
我不确定这是否会进入 C++14,或者是否会独立发布,但 GCC似乎已经支持这个。
这可能是一个不错的方法,具体取决于您的用例。声明以base
基类本身命名的基类的 typedef。
然后派生类X
将继承它作为 typename X::base
。
如此,如此。B::base
_A
C::base
A
struct A
{
typedef A base;
};
struct B : A {};
struct C : B {};
template<class X>
void f()
{
typename X::base x;
}
int main()
{
f<B>();
f<C>();
}
我想std::is_base_of
可以帮助你
#include <type_traits>
std::is_base_of<B, D>()
如果 D 派生自 B 或者如果两者都是相同的非联合类,则提供等于 true 的成员常量值。否则值为假。
您可以使用它来检查一个类是否是另一个类的基类:
std::is_base_of<A, A>() // Base<A>::Type == A
std::is_base_of<A, B>() // Base<B>::Type == A
std::is_base_of<A, C>() // Base<C>::Type == A
有一定的限制,这是可能的!
需要以这种方式检测的每个碱基都必须继承自某个 CRTP 碱基。(或者,可能包含某种宏。)
你会得到一份所有父母的名单,包括间接父母。
#include <cstddef>
#include <iostream>
#include <typeindex>
#include <utility>
template <typename T>
struct tag
{
using type = T;
};
template <typename ...P>
struct type_list
{
inline static constexpr std::size_t size = sizeof...(P);
};
namespace impl
{
constexpr void adl_ViewBase() {} // A dummy ADL target.
template <typename D, std::size_t I>
struct BaseViewer
{
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
friend constexpr auto adl_ViewBase(BaseViewer);
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
};
template <typename D, std::size_t I, typename B>
struct BaseWriter
{
friend constexpr auto adl_ViewBase(BaseViewer<D, I>) {return tag<B>{};}
};
template <typename D, typename Unique, std::size_t I = 0, typename = void>
struct NumBases : std::integral_constant<std::size_t, I> {};
template <typename D, typename Unique, std::size_t I>
struct NumBases<D, Unique, I, decltype(adl_ViewBase(BaseViewer<D, I>{}), void())> : std::integral_constant<std::size_t, NumBases<D, Unique, I+1, void>::value> {};
template <typename D, typename B>
struct BaseInserter : BaseWriter<D, NumBases<D, B>::value, B> {};
template <typename T>
constexpr void adl_RegisterBases(void *) {} // A dummy ADL target.
template <typename T>
struct RegisterBases : decltype(adl_RegisterBases<T>((T *)nullptr), tag<void>())
{};
template <typename T, typename I>
struct BaseListLow {};
template <typename T, std::size_t ...I>
struct BaseListLow<T, std::index_sequence<I...>>
{
static constexpr type_list<decltype(adl_ViewBase(BaseViewer<T, I>{}))...> helper() {}
using type = decltype(helper());
};
template <typename T>
struct BaseList : BaseListLow<T, std::make_index_sequence<(impl::RegisterBases<T>{}, NumBases<T, void>::value)>> {};
}
template <typename T>
using base_list = typename impl::BaseList<T>::type;
template <typename T>
struct Base
{
template <
typename D,
std::enable_if_t<std::is_base_of_v<T, D>, std::nullptr_t> = nullptr,
typename impl::BaseInserter<D, T>::nonExistent = nullptr
>
friend constexpr void adl_RegisterBases(void *) {}
};
struct A : Base<A> {};
struct B : Base<B>, A {};
struct C : Base<C> {};
struct D : Base<D>, B, C {};
template <typename T>
void printType()
{
#ifndef _MSC_VER
std::cout << __PRETTY_FUNCTION__ << '\n';
#else
std::cout << __FUNCSIG__ << '\n';
#endif
};
int main()
{
static_assert( base_list<D>::size == 4 );
printType<base_list<D>>(); // typeList<tag<A>, tag<B>, tag<C>, tag<D>>, order may vary
}
这是发生了什么:
friend
向需要以这种方式检测的每个类添加一个函数。这些函数在 SFINAE 中是不可调用的,但仅在重载决策期间考虑它们会实例化将相应基类附加到列表的模板。