Как объявить переменную, используя typeinfo.name C ++ - PullRequest
0 голосов
/ 30 декабря 2018

Я люблю кодирование, и обычно делаю это в Python из-за его простоты и мощности.
Однако в течение некоторых критически важных программ / задач я использую C ++.
Поэтому, чтобы получить лучшее из обоих миров, яЯ делаю Pythonesque список в C ++.

AIM: Я хотел бы иметь возможность добавить любую переменную или значение любого типа данных, , включая классы, которые пользователь определил .
Для этогоУ меня есть структура item с char * value, char * type и int size.
Мой List имеет массив этих item * с.


СейчасЯ взял переменную в шаблонной функции:
template<class T> item * encode(const T& var);
и объявил указатель на элемент item * i = new item;

И я сохранил значения этих переменных в виде строк в стиле c.
Например, 14675 в двоичном виде - 0000 0000 0000 0000 0011 1001 0101 0011
Поэтому я динамически создал пробел, например:
i->size = sizeof(var);
i->value = new char[i->size]; //4 in this case
и установил каждый бит в значениес соответствующими битами в var.

Я также сохранил их типы как
i->type = typeinfo(var).name();
Пока все хорошо!


Теперь я застрял с auto decode(item * i) -> decltype(/*What goes here???*/)
КакЯ указываю тип возвращаемого значения функции?
Есть ли какой-нибудь возможный способ?
Желательно использовать i->type?
Или я должен внести изменения в базовый дизайн этого процесса?
Спасибо зазаранее!

1 Ответ

0 голосов
/ 30 декабря 2018

Отвечая на ваш вопрос

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

Без сотрудничества с пользователем это невозможно в C ++.

Помните, что типы C ++ являются концепцией только во время компиляции.Они не существуют во время выполнения.Единственная информация о типе, доступная во время выполнения, это тонкий слой RTTI, предоставляемый typeid().Типизация утки во время выполнения, как в Python, невозможна.

Вы можете создать контейнер произвольных объектов довольно легко.

std::vector<std::any> v;  // requires C++17

Однако пользователь этого контейнера должен знать, что содержит индекс, чтотип:

if (v[0].type() == typeid(ArbitraryUserType)) {
    const auto& item = std::any_cast<ArbitraryUserType>(v[0]);
    // work on item ...
}

Из-за природы типов во время компиляции вы как автор библиотеки не можете выполнить это any_cast.Это должно быть прописано в исходном коде пользователя.

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

Примечания:

  • Без C ++ 17 вы могли быиспользуйте boost::any.
  • Если вы знаете список возможных типов во время компиляции, std::vector<std::variant<Type1, Type2, etc>> - хорошая альтернатива.С any пользователь несет полную ответственность за отслеживание их типов.Поскольку все проверки типов происходят во время выполнения, компилятор не может помочь.Variant, с другой стороны, возвращает большую часть безопасности во время компиляции.И снова есть boost::variant в качестве альтернативы, отличной от C ++ 17.

Замечания о подходе к кодированию

В основном вы пытаетесь сериализовать (кодировать) и десериализовать (декодировать)) произвольные типы.Без сотрудничества с этими типами это невозможно.

Ваш подход работает только для тривиальных типов, которые можно копировать по крупицам.В C ++ даже есть черта типа: std :: is_trivially_copyable .В конце концов, вы поддерживаете базовые типы и структуры в стиле Си, но ничего больше.

Представьте, что T для вашей функции encode() было std::string.Проще говоря, std::string содержит указатель на отдельно выделенный фрагмент памяти, где хранятся фактические строковые данные.Сам строковый объект является просто управляющей оболочкой для этого указателя.encode() только сериализует объект-оболочку, но не указывает на блок памяти с фактическими данными.

Даже если во время десериализации вы можете создать экземпляры произвольных типов из потока битов, поток не завершен.Вам нужно реализовать C ++ версию Python copy.deepcopy, которая невозможна без взаимодействия с каждым типом.Взгляните на библиотеку сериализации C ++ - возьмите Cereal в качестве простого примера - чтобы увидеть, как это сотрудничество может выглядеть на практике.

...