2009-03-29 3 views
5

При использовании макроса BOOST_SERIALIZATION_NVP для создания пары имя-значение для сериализации XML компилятор с радостью позволяет скомпилировать следующий код, хотя имя элемента не является допустимым XML элемент и исключение брошено при попытке фактически сериализовать объект в XML:ускорить сериализацию макросов NVP и символов не-XML-элементов

BOOST_SERIALIZATION_NVP(_member[index]) 

очевидное исправление заключается в использовании:

boost::serialization::make_nvp("ValidMemberName", _member[index]) 

Но кто может предложить способ изменить импульс так, что незаконнорожденный элемент имена будут вызывать компиляцию n ошибка? (Таким образом, не полагаясь на модульное тестирование, чтобы поймать выше тонкого бага)


Edit:

Одна идея состоит в том, чтобы как-то объявить фиктивный локальную переменную с именем элемента, переданного в макрос, предполагая, что набор допустимых идентификаторов в C++ является подмножеством действительных элементов XML. Не все уверены, что это можно сделать.

+0

Это приведет к ошибке времени выполнения 'what(): Недопустимое имя тега XML. – alfC

ответ

1

Я думаю, что ваша идея, вероятно, будет работать. Действительные идентификаторы C++ состоят из A-Z, a-z, 0-9 и подчеркивания, что на самом деле является надлежащим подмножеством идентификаторов XML (которые добавляют набор дефисов, период и набор символов Unicode в набор).

Вы можете попробовать конструкцию, как это, чтобы получить ошибку во время компиляции:

#define SAFE_BOOST_SERIALIZATION_NVP(name) \ 
    { int name = 0; } ; BOOST_SERIALZATION_NVP(name) 

Скобки ограничивают сферу фиктивной переменной только что строки, так что вы не загромождать функцию с фиктивными переменными , Вероятно, компилятор также оптимизирует эту фиктивную переменную, поэтому нет затрат времени исполнения. Когда я использую этот макрос в следующем коде, я получаю error: invalid intializer:

#include "boost/serialization/nvp.hpp" 
#define SAFE_BOOST_SERIALIZATION_NVP(name) \ 
    { int name = 0; } ; BOOST_SERIALIZATION_NVP(name) 

int main(int argc, char *argv[]) 
{ 
    int foo[3] = { 10, 20, 30 }; 
    int bar = 10; 
    SAFE_BOOST_SERIALIZATION_NVP(foo[0]); 
    return 0; 
} 

Если я заменяю foo[0] с bar в вызове SAFE_BOOST_SERIALIZATION_NVP, он компилируется без ошибок.

+1

Но я не думаю, что это сработает при использовании в функции serialize. serialize (..) {archive & SAFE_BOOST_SER_NVP (m); } ... –

+0

@AssafLavie, вы правы, однако эта небольшая модификация (дополнительный код в конце), похоже, выполняет задание: '#define SAFE_BOOST_SERIALIZATION_NVP (name) \ BOOST_SERIALIZATION_NVP (имя); {int name = 0;} ' – alfC

2

Цитирование синтаксис XML для имен:

NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] 
NameChar  ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040] 

Я вижу следующие различия с именами C++: Leading _ могут быть зарезервированы в C++, в зависимости от того, что следует; двоеточие, точки и знаки минус действительны в именах XML. Символы Unicode могут также вызвать некоторое горе в C++, но это в основном зависит от реализации.

Часть [# x0300- # x036F] объединяет акценты (диакритические знаки), что может быть дополнительным беспокойством по поводу равенства имен.

Итак, нет решения, которое ловит не-алфавитные символы. < ::: /> может выглядеть как смайлик, но это хорошо сформированный XML. В остальном ваша идея в порядке. Идея Эрика Мельски - приятная попытка, но она принимает много неа-алфавитных символов. Например, foo[1], &foo, *foo, foo=0 или foo,bar. Есть лучшая альтернатива: {using namespace name;}. Это примет foo::bar, но на самом деле это нормально - foo :: bar разрешено в XML.

+0

Но если' name' еще не является пространством имен, это приведет к ошибке. – alfC

1

Это гибрид между двумя ответами, @ Eric Melski (в основном правильный --extra код должен быть в конце define - но неполное решение - некоторые запрещенные имена не «фильтруются» -) и @MSalters ' в основном правильные (- using namespace не могут использоваться для произвольных необъявленных имен -).

Я предлагаю с помощью struct:

#define SAFE_BOOST_SERIALIZATION_NVP(name) \ 
    BOOST_SERIALIZATION_NVP(name); {struct name{};} 

или более рискованными:

#undef BOOST_SERIALIZATION_NVP 
#define BOOST_SERIALIZATION_NVP(name)        \ 
    boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), name); {struct name{};} 

Излишне говорить, что нет затрат времени выполнения для этого.

Смежные вопросы