是否可以在类层次结构中获取基类类型?
例如:
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
这可能吗?我有多重继承的情况怎么样?
答案 0 :(得分:19)
C ++中的类可以有多个基类,所以没有任何意义可以“获得 基础”特征。
但是,TR2的添加包括新的编译器支持的特征std::tr2::bases
和std::tr2::direct_bases
,它返回基类的不透明类型列表。
我不确定这是否会进入C ++ 14,或者是否会独立发布,但GCC已经seems to support this。
答案 1 :(得分:6)
我认为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
答案 2 :(得分:4)
根据您的使用情况,这可能是一种很好的方法。在基类本身中声明一个名为base
的基类的typedef。
然后派生类X
会将其作为类型名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>();
}
答案 3 :(得分:0)
在某些限制下,这是可能的!
需要以这种方式检测的每个碱基都必须从某个 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, 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 使这些函数无法调用,但仅在重载解析期间考虑它们就会实例化将相应基类附加到列表中的模板。