Введите trait для определения основного базового класса

Если у меня есть класс Base, по крайней мере, с одной виртуальной функцией и классом Derived, который наследуется отдельно от этого, то (uintptr_t)derived - (uintptr_t)static_cast<Base*>(derived) гарантировано (Itanium ABI) равным нулю, хотя Derived не является стандартной компоновкой. Однако в общем случае это не обязательно верно (например, множественное наследование).

Можно ли написать черту, которую можно использовать для определения, является ли один класс основным базовым классом другого?

Полезные разделы от Itanium ABI:

http://refspecs.linux-foundation.org/cxxabi-1.83.html

Первичный базовый класс

Для динамического класса — уникальный базовый класс (если есть), с которым он разделяет виртуальный указатель со смещением 0.
Это первый (в прямом порядке базового класса) не виртуальный динамический базовый класс, если таковой существует.

Динамический класс

Класс, требующий указателя виртуальной таблицы (потому что он или его базы имеют одну или несколько виртуальных функций-членов или виртуальных базовых классов).

8

Решение

Это будет частью следующего стандарта Это было частью прерванного TR2 через std::bases а также std::direct_bases черты. Если вы работаете с компилятором, который включает черновик TR2, возможно, у вас есть поддержка для этого. Например, в GCC 4.7.2:

#include <demangle.hpp>
#include <iostream>
#include <tr2/type_traits>

struct T1 { };
struct T2 { };
struct Foo : T1, T2 { };int main()
{
std::cout << demangle<std::tr2::direct_bases<Foo>::type>() << std::endl;
}

Это печатает:

std::tr2::__reflection_typelist<T1, T2>

(Деманглер мой; вы, возможно, видели это в другом месте.)

Я верю, что вы можете построить подходящую «полиморфную и точно равную нулю или одной основе» черту себя.

8

Другие решения

Ниже приведена дикая, не полностью протестированная попытка сделать что-то полезное только с C ++ 11 (на самом деле это не так. действительно требуется любая функция C ++ 11, но так проще написать).

Тем не менее, эта черта только проверяет транзитивное закрытие свойства «является первичным базовым классом»: я не смог найти ненавязчивый способ проверить, является ли класс непосредственный базовый класс другого класса.

#include <type_traits>

template<typename B, typename D, D* p = nullptr, typename = void>
struct is_primary_base_of : std::false_type { };

template<typename B, typename D, D* p>
struct is_primary_base_of<B, D, p,
typename std::enable_if<
((int)(p + 1024) - (int)static_cast<B*>(p + 1024)) == 0
>::type
>
:
std::true_type { };

Вот пример:

struct A { virtual ~A() { } };

struct B : A { };

struct C { virtual ~C() { } };

struct D : B, C { };

struct E : virtual A, C { };

int main()
{
// Does not fire (A is PBC of B, which is PBC of D)
static_assert(is_primary_base_of<A, D>::value, "Error!");

// Does not fire (B is PBC of C)
static_assert(is_primary_base_of<B, D>::value, "Error!");

// Fires (C is not PBC of D)
static_assert(is_primary_base_of<C, D>::value, "Error!");

// Fires (A is inherited virtually by E, so it is not PBC of E)
static_assert(is_primary_base_of<A, E>::value, "Error!");

// Does not fire (C is the first non-virtual base class of E)
static_assert(is_primary_base_of<C, E>::value, "Error!");
}
0

По вопросам рекламы [email protected]