Создание сериализуемых уникальных идентификаторов времени компиляции для произвольных UDT - PullRequest
3 голосов
/ 09 января 2011

Мне нужен общий способ создания уникальных идентификаторов времени компиляции для любых пользовательских типов C ++.
Например:

unique_id<my_type>::value == 0 // true
unique_id<other_type>::value == 1 // true  

Мне удалось реализовать что-то подобное с использованием мета препроцессора.программирование, проблема в том, что сериализация не соответствует.Например, если шаблон класса unique_id сначала создается с other_type, то любая сериализация в предыдущих ревизиях моей программы будет признана недействительной.

Я искал решения этой проблемы и нашел несколько способовреализовать это с помощью непоследовательной сериализации, если уникальные значения являются константами времени компиляции.Если используются RTTI или аналогичные методы, такие как boost::sp_typeinfo, то уникальные значения, очевидно, не являются константами времени компиляции, и присутствуют дополнительные издержки.Специальным решением этой проблемы будет создание всех уникальных идентификаторов в отдельном заголовке в правильном порядке, но это требует дополнительного обслуживания и стандартного кода, который не отличается от использования enum unique_id{my_type, other_type};.

Хорошим решением этой проблемы было бы использование пользовательских литералов, к сожалению, насколько мне известно, ни один компилятор не поддерживает их в данный момент.Синтаксис будет 'my_type'_id; 'other_type'_id; с UDL.

Я надеюсь, что кто-нибудь знает хитрость, которая позволяет реализовать сериализуемые уникальные идентификаторы в C ++ с текущим стандартом (C ++ 03 / C ++ 0x), я был бы рад, если бы он работал с последнимистабильные компиляторы MSVC и GNU-G ++, хотя я ожидаю, что если есть решение, оно не переносимо.

Я хотел бы пояснить, что использование mpl::set или подобных конструкций, таких как mpl::vector и фильтрация, делаетне решить эту проблему, потому что область действия мета-набора / вектора ограничена и фактически вызывает больше проблем, чем просто метапрограммирование препроцессора.

Ответы [ 3 ]

2 голосов
/ 10 января 2011

Некоторое время назад я добавил шаг сборки в один мой проект, что позволило мне записать @script_name(args) в исходный файл C ++ и автоматически заменить его на вывод соответствующего сценария, например ./script_name.pl args или ./script_name.py args.

Вы можете отказаться от идеи загрязнения языка в нестандартный C ++, но все, что вам нужно сделать, это написать @sha1(my_type), чтобы получить уникальный целочисленный хэш имени класса, независимо от порядка сборки и без необходимости явная реализация.

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

1 голос
/ 10 января 2011

Сохранение данных - очень интересная проблема.

Мой первый вопрос: вы действительно хотите сериализацию ?Если вы готовы исследовать альтернативу, тогда переходите к следующему разделу.

Если вы все еще там, я думаю, что вы не дали решение typeid в полном объеме.

// static detection
template <typename T>
size_t unique_id()
{
  static size_t const id = some_hash(typeid(T)); // or boost::sp_typeinfo
  return id;
}

// dynamic detection
template <typename T>
size_t unique_id(T const& t)
{
  return some_hash(typeid(t)); // no memoization possible
}

Примечание: я использую локальный статический код, чтобы избежать проблемы с порядком инициализации, если это значение требуется до ввода main

Это очень похоже на ваш unique_id<some_type>::value и хотя он вычисляется во время выполнения, он вычисляется только один раз, а затем результат (для статического обнаружения) запоминается для будущих вызовов.

Также обратите внимание, что он полностью универсален: нет необходимости явно писатьфункция для каждого типа.


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

  • вам нужно создать версию представления, чтобы иметь возможность декодировать "более старые" версии
  • работа с прямой совместимостью довольно трудна
  • работа с циклической ссылкой довольно сложнаard (некоторые фреймворки его обрабатывают)
  • , а затем возникает проблема перемещения информации из одной в другую -> десериализация старых версий становится грязной и разочаровывающей

Для постоянных сохранений яобычно рекомендуют использовать специальную спецификацию.Думайте о сохраненных данных как о сообщении вашей будущей личности.И я обычно делаю все возможное, чтобы предложить великолепную библиотеку Google Proto Buffer:

  • Совместимость с обратной и прямой совместимостью
  • Несколько выходных форматов -> удобочитаемый для человека (для отладки) илидвоичный
  • Несколько языков могут читать / писать одни и те же сообщения (C ++, Java, Python)
0 голосов
/ 10 января 2011

Я уверен, что вам придется реализовать собственное расширение, чтобы это произошло, я не видел и не слышал о такой конструкции во время компиляции.MSVC предлагает __COUNTER__ для препроцессора, но я не знаю ни одного шаблона.

...