Вектор typedefs

Возможно ли ЛЮБЫМ способом иметь вектор типа (def) в C++11/14?

Первое, что я попробовал, это иметь вектор базового класса и каким-то образом получить typedef из его производной формы, но я не могу заставить это работать, что бы я ни пытался (скорее всего, это невозможно).

Псевдо-C++:

class base
{
   /* somehow access 'type' from derived */
}

template <typename T>
class derived : base
{
   typedef T type;
}

vector<base*> vec;
vec.push_back( new derived<int> );
vec.push_back( new derived<double> );
vec.push_back( new derived<float> );
vec.push_back( new derived<string> );

for(auto& item : vec)
   static_cast< item->type >( /* something */ );

person user1233963    schedule 23.10.2013    source источник
comment
Нет, и похоже, что вам нужен вектор интеллектуальных указателей или ссылочных оболочек (я бы порекомендовал первый из этих двух). Но вам все равно нужно знать производный тип, чтобы даже запрашивать его.   -  person WhozCraig    schedule 23.10.2013
comment
Чего именно вы хотите добиться? Я могу сделать class SomeClass; typedef SomeClass X; std::vector<X> v; без проблем.   -  person rwols    schedule 23.10.2013
comment
Возможно, вы ищете что-то вроде Boost.MPL или Boost.Fusion ?   -  person Angew is no longer proud of SO    schedule 23.10.2013
comment
@rwols: это не то, о чем я прошу. Что мне нужно, так это иметь вектор typedef, который ссылается на разные типы.   -  person user1233963    schedule 23.10.2013
comment
Вы можете написать using my_types = std::tuple<T1, T2, T3>. Затем вы можете проиндексировать его с помощью std::tuple_element.   -  person zch    schedule 23.10.2013
comment
std::vector является мономорфным, т. е. может содержать объекты только одного статического типа. Может быть, вам стоит заглянуть в Boost.Variant?   -  person Xeo    schedule 23.10.2013
comment
@Xeo: ты приближаешься. Проверьте мое редактирование для большей ясности   -  person user1233963    schedule 23.10.2013
comment
вариант вам не поможет, так как кажется, что вам нужна каждая запись в векторе, вариант будет содержать только один экземпляр. Я бы порекомендовал std::tuple или boost::fusion::vector.   -  person Nim    schedule 23.10.2013
comment
Взгляните на Boost.MPL или Boost.Fusion. Это делает то, что вы хотите.   -  person Konrad Rudolph    schedule 23.10.2013
comment
@Nim: fusion::vector выглядит хорошо. Хотите опубликовать ответ с примером?   -  person user1233963    schedule 23.10.2013
comment
Если вы расширите свой вопрос о том, каково намерение с static_cast, возможно, это возможно. В нынешнем виде не совсем понятно, что вам нужно..   -  person Nim    schedule 23.10.2013
comment
Это для преобразования указателей void в типы в векторе   -  person user1233963    schedule 23.10.2013


Ответы (4)


Boost MPL предоставляет для этого конструкцию времени компиляции, например:

typedef boost::mpl::vector<int, double, std::string, CustomA, CustomB> seq_of_types;

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

Boost Fusion (и std::tuple) вмешивается здесь, чтобы предоставить гетерогенный контейнер во время выполнения, например

boost::fusion::vector<int, double, std::string> v{10, 100., "Foo"};

Теперь во время компиляции у вас есть доступ к информации о типе каждой записи, а во время выполнения у вас есть экземпляр каждого типа в последовательности для работы.

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

В качестве альтернативы то же самое возможно, не прибегая к использованию наследования, если вы используете вариативный тип, такой как boost::variant, например:

std::vector<boost::variant<int, double, std::string>> entries;

Теперь каждая запись является одним из типов int, double, std::string. Затем по мере повторения вы можете использовать статического посетителя для работы с конкретным экземпляром. Я думаю, что некоторое время назад я ответил на вопрос о SO, который демонстрирует это.

Так что же это будет?

РЕДАКТИРОВАТЬ: основываясь на вашем последнем комментарии, последний (вариант) на самом деле не летает, как и простое наследование. Я думаю, что вектор слияния действительно не нужен, так как вам не нужен экземпляр каждого типа. Тогда наиболее подходящим для вас является mpl::vector и используйте функцию времени выполнения mpl::for_each

person Nim    schedule 23.10.2013

Возможно, вы могли бы заглянуть в списки типов Loki (см. здесь). Есть вопрос по их использованию здесь. Я думаю, что это максимально близко к тому, что вы ищете. Boost MPL также имеет что-то подобное (см. этот вопрос), с списки типов и векторы типов.

person jbat100    schedule 23.10.2013

Нет, ты не можешь. Типы в C++ не являются объектами, и их нельзя использовать в качестве значений.

В зависимости от того, что вам действительно нужно, вы можете что-то сделать с type_info (точнее, с указателями на них). Это не тот тип, и его нельзя использовать для доступа к типу, но его можно использовать, например, при сравнении на равенство, чтобы определить, относятся ли два объекта type_info к одному и тому же или к разным типам.

person Steve Jessop    schedule 23.10.2013

Зависит от того, что вы подразумеваете под «вектором»

Специализация std::tuple — это упорядоченная (во время компиляции) коллекция типов. Вы можете проиндексировать их (непроверенный код):

 typedef std::tuple<int, long, void, std::string, std::complex<float> Tuple;
 typename std::tuple_element<1, Tuple>::type foo; // foo is of type long

Вы можете выполнять всевозможные манипуляции (во время компиляции) с кортежами, и результатом этих манипуляций являются типы (или другие кортежи). С++ 14 формализует (но не изобретает) идею "индексных последовательностей", которые позволяют выполнять практически произвольные преобразования типа кортежа -> типа кортежа.

person Marshall Clow    schedule 28.10.2013