Как получить тип из type_info для параметров шаблона

У меня есть дерево, где каждый узел в основном выглядит так:

struct node
{
std::unordered_set<object*> objects;
std::map<std::type_index,node> children;
};

Когда я перебираю дерево, чтобы добавить новый тип, я хочу сделать проверку:

std::is_base_of<base,derived>

Тем не менее, единственная информация, которую я имею для производного типа, это type_index/type_info*,

В любом случае я могу преобразовать type_info* к template аргумент?

Если нет, каковы мои другие варианты? Я думаю, можно позвонить decltype(*objects.begin()), но это потребовало бы, чтобы каждый набор в каждом узле никогда не был пустым.

3

Решение

Если я вас правильно понял, вы хотите тип inheritance_checker так что каждое его назначение связано с типом, но inheritance_checker само по себе нет. Что-то похожее type_ifo но это может проверить отношения наследования во время выполнения. Например, вы хотите, чтобы следующее работало:

class A {};
class B : public A {};

// Note that a and b have the same type but they are "related" to distinct types.
inheritance_checker a = inheritance_checker::create<A>();
inheritance_checker b = inheritance_checker::create<B>();

assert(   a.is_base_of  (b) );
assert(   a.derives_from(a) ); // derives from or is equal to
assert( ! b.is_base_of  (a) );
assert(   b.derives_from(b) ); // derives from or is equal to

Если это так, я могу предложить вам кое-что, что, к сожалению, может быть довольно медленным! Это зависит от исключений.

Основная идея заключается в том, что если вы бросаете B* затем catch (A*) это матч. Следовательно, мы даем inheritance_checker способность бросать и ловить указатели на тип, указанный во время строительства. Но inheritance_checker не является шаблоном, и поэтому эта емкость должна быть предоставлена ​​стертым способом. Это может быть сделано путем сохранения указателей на функции, которые имеют фиксированную сигнатуру, которая не зависит от типа, переданного при построении, но способна бросать / перехватывать указатели на данный тип. Возможная реализация inheritance_checker дается ниже.

#include <cassert>

class inheritance_checker {

typedef void (*thrower_t)();
typedef bool (*catcher_t)(thrower_t);

public:

template <typename T>
static inheritance_checker create() {
return inheritance_checker(concrete_thrower<T>, concrete_catcher<T>);
}

bool is_derived_from(const inheritance_checker& other) const {
return other.catcher_(thrower_);
}

bool is_base_of(const inheritance_checker& other) const {
return catcher_(other.thrower_);
}

private:

template <typename T>
static void concrete_thrower() {
throw static_cast<T*>(nullptr);
}

template <typename T>
static bool concrete_catcher(thrower_t thrower) {
try         { thrower();   }
catch (T*)  { return true; }
catch (...) {              }
return false;
}

inheritance_checker(thrower_t thrower, catcher_t catcher) :
thrower_(thrower), catcher_(catcher) {
}

thrower_t thrower_;
catcher_t catcher_;
};

class A {};
class B : public A {};
class C : public B {};
class D {};

int main() {

auto a = inheritance_checker::create<A>();
auto b = inheritance_checker::create<B>();
auto c = inheritance_checker::create<C>();
auto d = inheritance_checker::create<D>();

assert( a.is_base_of(a));
assert( a.is_base_of(b));
assert( a.is_base_of(c));
assert(!a.is_base_of(d));

assert( a.is_derived_from(a));
assert(!a.is_derived_from(b));
assert(!a.is_derived_from(c));
assert(!a.is_derived_from(d));

assert(!b.is_base_of(a));
assert( b.is_base_of(b));
assert( b.is_base_of(c));
assert(!b.is_base_of(d));

assert( b.is_derived_from(a));
assert( b.is_derived_from(b));
assert(!b.is_derived_from(c));
assert(!b.is_derived_from(d));

assert(!c.is_base_of(a));
assert(!c.is_base_of(b));
assert( c.is_base_of(c));
assert(!c.is_base_of(d));

assert( c.is_derived_from(a));
assert( c.is_derived_from(b));
assert( c.is_derived_from(c));
assert(!c.is_derived_from(d));

assert(!d.is_base_of(a));
assert(!d.is_base_of(b));
assert(!d.is_base_of(c));
assert( d.is_base_of(d));

assert(!d.is_derived_from(a));
assert(!d.is_derived_from(b));
assert(!d.is_derived_from(c));
assert( d.is_derived_from(d));
}

Если вы хотите, вы можете добавить type_info* участник inheritance_checker чтобы получить дополнительную функциональность, которая type_info обеспечивает.

Обратите внимание на симметрию между is_base_of а также derives_from, На самом деле, вы можете удалить один из них.

Я предлагаю вам прочитать этот статья.

4

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

В любом случае я могу преобразовать type_info* к аргументу шаблона?

Нет, нет пути. Шаблоны — это время компиляции, RTTI — время выполнения. Нет связи между ними.

Я думаю, можно позвонить decltype(*objects.begin()), но это потребовало бы, чтобы каждый набор в каждом узле никогда не был пустым.

Это не потребует этого. decltype не оценивает свои аргументы — это не нужно. Нужно только проверить типы. Вы можете счастливо сделать decltype(*a_null_pointer) без вызова UB, так как выражение никогда не вычисляется — это так называемое недооцененный контекст. sizeof принадлежит к той же категории.

Обратите внимание, что это не слишком дорого для вас — вы просто получите object*& назад. Обычно вы не можете получить тип из информации времени выполнения без предварительной подготовки отображения.

6

is_base_of а также decltype являются чисто компилируемыми временными конструкциями; они не будут отражать динамический тип ваших объектов.

type_info не предоставляет возможности для проверки отношений подкласса; единственный способ выполнить эту проверку во время выполнения — использовать dynamic_cast, Вам нужно будет хранить unique_ptr<base> и посмотрим, сможет ли он dynamic_cast к производному типу.

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