2015-05-12 2 views
0

Мне было интересно, есть ли способ сделать следующее в лучшем виде (легче читать, менее многословно).переключатель в зависимости от типа объекта

У меня есть объект Foo, который имеет конкретные типы реализации Foo, позволяет называть их Foo1 .. FooN.

У меня также есть строковая таблица описаний foo, например Foo1 «бары Foo1». То, что я хочу сделать, - это какая-то проверка типа в зависимости от того, какой тип Foo подходит для работы. В настоящее время я делаю:

std::string fooUtils::translate(Foo * foo){ 
    if(typeid(foo) == typeid(Foo1){ 
     return "bars the Foo1"; 
    } 
    else if 
    ... 
} 

Мне было интересно, есть ли лучший способ сделать это.

Первое, что я думаю о хранении std :: map < std :: typeinfo, std :: string> - это решение, на которое я стремлюсь, но я не знаю о каких-либо побочных эффектах введите информацию в качестве ключа к карте (есть ли какие-либо?). Мне также было интересно, есть ли что-нибудь, чтобы сравнивать типы в менее подробном виде, например boost :: is_type < Foo1, foo> или что-то вроде этого.

+1

Вы не можете хранить 'typeinfo' напрямую в контейнере, поскольку 'typeinfo' не имеет общих конструкторов. Должен быть хитрым. –

+2

Поиск функции шаблона type2enum в Google. Он создает перечисление из каждого из ваших типов (ваши классы), поэтому вы можете использовать перечисление в своем коммутаторе – madduci

ответ

2

Вот type_info утилита поиска:

template<class T, class...Ts> 
std::array<std::decay_t<T>, sizeof...(Ts)+1> make_array(T&& t, Ts&&...ts) { 
    return {{ std::forward<T>(t), std::forward<Ts>(ts)... }}; 
} 
template<class F, class T, size_t N> 
std::array<T, N> sorted(std::array<T, N> arr) { 
    std::sort(begin(arr), end(arr), F{}); 
    return arr; 
} 
struct p_type_info_sort { 
    bool operator()(std::type_info const* lhs, std::type_info const* rhs) const { 
    return lhs->before(*rhs); 
    } 
}; 

template<class...Ts, class T> 
std::type_info const* which(T const& t) { 
    static const auto table=sorted<p_type_info_sort>(make_array(
    (&typeid(Ts))... 
)); 
    auto r = std::equal_range(begin(table), end(table), &typeid(t), p_type_info_sort{}); 
    if (r.first==r.second) return nullptr; 
    return *r.first; 
} 

вы делаете which<A, B, C, D>(*a) и возвращает который списка типов экземпляра *a соответствует точно (динамически). Он делает это, возвращая type_info const* и nullptr, если не удается найти совпадение.

Теперь это, как правило, плохая идея. Вышеуказанные только точные соответствия. Обычно, если у вас такой полиморфизм, вы захотите поместить его в интерфейс, и в противном случае у вас, вероятно, есть и другие недостатки дизайна.

live example

+0

Я думаю, что это не сработает, потому что количество подклассов ... Также каждый раз, когда вы добавляете подкласс, вам нужно добавить его в свой список параметров <>. – cerkiewny

+0

@cerkiewny да? Вы попросили «переключатель» между типами. 'switch' требует, чтобы каждый 'case' был указан. – Yakk

+0

О, я сначала не получил ваш ответ, поэтому вы просто измените std :: map на std :: map , сделайте выбор шаблона в функции, а затем на основе выбранная информация о типе выберете строку из std :: map? но как вы создаете std :: map ? – cerkiewny

8

Вот какие функции virtual-члены для:

std::string fooUtils::translate(Foo * foo) { 
    foo->translate(); 
} 

С:

struct Foo { 
    virtual std::string translate() const { return "base"; } 
}; 

struct Foo1 : Foo { 
    std::string translate() const override { 
     return "bars the Foo1"; 
    } 
}; 
+0

, как бы вы шли по итерации по всем типам тогда? Вам понадобится какая-то коллекция всех возможных подтипов типа? – cerkiewny

+1

@cerkiewny Нет итераций, нет коллекции подтипов. Мы просто используем динамическую отправку, чтобы выбрать правильный тип во время выполнения. – Barry

+0

Возможно, я не задал вопрос достаточно ясно, но я хочу остаться с моим текущим подходом, поэтому сохраните строку, связанную с типом, и выберите из коллекции в зависимости от входящего типа, что вы предложили совершенно по-другому. Это не сработает для меня, поскольку мне нужно иметь доступ ко всей информации вместе. – cerkiewny

0

В этой теме вы можете найти преобразование type2enum и обратное преобразование enum2type: How to do a typed parameter package class?

Выдержка из ответа:

template<class T> type2enum(); 
#define TYPE2ENUM_SPEC(TYPE, ENUM) \ 
template<> type2enum<TYPE>() \ 
{ return ENUM; } 

enum { T1enum, T2enum, T3enum } 
TYPE2ENUM_SPEC(type1_t, T1enum); 
TYPE2ENUM_SPEC(type2_t, T2enum); 
TYPE2ENUM_SPEC(some_third_type_t, T3enum);