#c #templates #yaml-cpp
#c #шаблоны #yaml-cpp
Вопрос:
Я делаю какую-то сериализацию с использованием yaml-cpp. Чтобы это сработало, каждый класс должен объявить метод с использованием подписи:
template <typename T> void Serialize(Tamp; s);
Это T
другой класс при сохранении и загрузке. Интерфейс двух классов одинаков, но я не могу создать абстрактный базовый класс, поскольку большинство методов являются шаблонами. Эта часть работает правильно. Я пытался подключить его с YAML::Node
помощью ‘s operator>>
и YAML::Emitter
‘s operator<<
.
У operator<<
меня есть рабочее решение, хотя и очень жестокое. Сначала объявите суперкласс для всех сериализуемых классов:
template <typename T> class Serializable {};
Тогда я могу использовать следующее operator<<
:
template <typename T>
YAML::Emitteramp; operator<<(YAML::Emitteramp; out,
Serializable<T>amp; val)
{
Serializer serializer(out);
reinterpret_cast<T*>(amp;val)->Serialize(serializer);
return out;
}
Это работает до сих пор, хотя это reinterpret_cast
выглядит довольно страшно, и я не уверен, что это вообще законно. Я пробовал то же самое для operator>>
, но это не сработало. Это выглядит так:
template <typename T>
void operator>>(const YAML::Nodeamp; node,
Serializable<T>amp; val)
{
Deserializer deserializer(node);
reinterpret_cast<T*>(amp;val)->Serialize(deserializer);
}
Но gcc (4.6.2) и clang (2.9) игнорируют его и используют operator>>
определенный в nodeimp.h (часть yaml-cpp):
template <typename T>
inline void operator >> (const Nodeamp; node, Tamp; value) {
if(!ConvertScalar(node, value))
throw InvalidScalar(node.m_mark);
}
Итак, мой вопрос: как мне это решить? Я абсолютно хочу иметь только один метод как для сериализации, так и для десериализации, и иметь возможность использовать >> и << , как если бы это был обычный тип, поддерживаемый yaml-cpp.
Ответ №1:
Во-первых, о reinterpret_cast
: вы действительно хотите static_cast
. В вашем случае вы знаете, что val
это a T
(а не просто a Serializable<T>
), поэтому вы можете использовать его напрямую.
Здесь я предполагаю, что вы объявляете свои классы как
class Foo: public Serializable<Foo> { ... };
reinterpret_cast
будет интерпретировать байты val
как a T
, что не гарантирует работу, но, вероятно, работает в вашем случае, потому что у вас одно наследование и Serializable<T>
не добавляет никаких переменных-членов.
Далее, перейдем к вашей реальной проблеме: это ошибка в yaml-cpp, и теперь она исправлена (r52790a15757d, если вы следите за репозиторием mercurial, и смотрите http://code.google.com/p/yaml-cpp/issues/detail?id=126 для вопроса, который я открыл).
С приведенным выше исправлением я считаю, что ваш код должен работать. Если вы не следите за репозиторием, разница довольно мала — вы можете исправить ее в своей версии yaml-cpp.
Комментарии:
1. странно, я пробовал
static_cast
, и это не сработало, но теперь это работает. (Может быть, я пытался привести к T, а не к T *?). В любом случае ваш патч отлично работает, спасибо за исправление.