Определить общий базовый класс

Предположим, что у каждого есть иерархия классов без множественного наследования:

struct TOP{};
struct L : TOP{};
struct R : TOP{};
struct LL : L{};
struct LR : L{};
struct RL : R{};
struct RR : R{};

Можно ли написать метафункцию, которая будет возвращать тип общей базы двух типов? (это может вернуться void если не общий базовый класс существует.)
Например

common_base<RR, R>::type == R
common_base<RL, RR>::type == R
common_base<LL, RR>::type == TOP
common_base<LL, std::string>::type == void

Очевидно, что это не будет работать с множественным наследованием, но я сосредоточен на одном случае наследования.

Во-первых, это кажется невозможным без некоторого самоанализа базового класса. Итак, у меня есть эта более простая проблема, сделать это таким образом, чтобы каждое предложение знало свою базу (внутренним base типа), например:

struct LR : L{using base = L;};

Даже таким образом я не могу понять метапрограммирование правильно.

Также я где-то читал (сейчас не могу найти), что GCC имеет некоторые расширения для определения общего базового класса. Это тот случай?

7

Решение

Был в какой-то момент основы а также direct_bases в std :: tr2 но это не было включено. У некоторых версий gcc есть это. Используя их, возможно, вы сможете получить то, что хотите.

3

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

Если у вас есть псевдоним каждого класса, база как base (как показано ниже), это можно сделать.

struct Child : Parent { using base = Parent; }; //typedef works too

Я создал struct:

template <class T1, class T2>
struct CommonBase;

CommonBase работает, сравнивая каждую базу T2 в T1, Когда он достигает основания верхнего уровня, он снова начинается снизу, но сравнивается с основанием T1,

Например: CommonBase<RL, RR> будет проходить следующие проверки:

RL !=  RR
RL !=  R
RL !=  Top
R  !=  RR
R  ==  R

Так CommonBase<RL, RR>::type == R, Если нет общей базы, type == void,

Я поставил код в конце, потому что метапрограммирование шаблона очень красиво:

#include <type_traits>

template <class T>
struct GetBase //type = T::base, or else void
{
template <class TT> static typename TT::base& f(int);
template <class TT> static void f(...);
typedef std::remove_reference_t<decltype(f<T>(0))> type;
};

template <class T1, class T2>
struct Compare2 //Compares T1 to every base of T2
{
typedef typename GetBase<T2>::type _type;
template <class T, bool = !std::is_same<T, void>::value>
struct helper
{
typedef typename Compare2<T1, T>::type type;
};
template <class T>
struct helper<T, false>
{
typedef void type;
};
typedef typename helper<_type>::type type;
};

template <class T>
struct Compare2<T, T>
{
typedef T type;
};

template <class T1, class T2>
struct Compare1 //Uses Compare2 against every base of T1
{
typedef typename GetBase<T1>::type _type;
template <class T, bool = !std::is_same<T, void>::value>
struct helper
{
typedef typename Compare1<T, T2>::type type;
};
template <class T>
struct helper<T, false>
{
typedef void type;
};
typedef std::conditional_t<std::is_same<typename Compare2<T1, T2>::type, void>::value, typename helper<_type>::type, typename Compare2<T1, T2>::type> type;
};

template <class T>
struct Compare1<T, T> //Probably redundant
{
typedef T type;
};

template <class T1, class T2>
struct CommonBase //You can throw a std::enable_if on this to limit it to class types
{
typedef typename Compare1<T1, T2>::type type;
};

Вот Вы можете увидеть это на некоторых тестах.

1

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