【发布时间】:2018-05-31 00:12:25
【问题描述】:
我正在尝试或多或少地序列化模板类MState<T>。为此,我有一个父抽象类MVariable,它用这种形式实现了几个序列化函数:
template <class Serializer, class SerializedType>
void serialize(Serializer& s, const SOME_SPECIFIC_TYPE &t) const;
我想让T 成为几乎任何东西。序列化是通过RapidJSON::Writer 在 JSON 中完成的。正因为如此,我需要使用特定的成员函数(例如Writer::String、Writer::Bool、Writer::Uint...)以便为每种类型获得正确的格式T。
基本类型和 STL 容器的序列化将由MVariable 提供。但是,我没有提供每一种类型(例如,将 SOME_SPECIFIC_TYPE 替换为 float、double、bool 等),而是尝试实现一个似乎存在一些缺陷的基于 SFINAE 的解决方案。
我有一组像这样的 typedef 定义和序列化函数:
class MVariable
{
template <class SerT> using SerializedFloating =
typename std::enable_if<std::is_floating_point<SerT>::value, SerT>::type;
template <class SerT> using SerializedSeqCntr =
typename std::enable_if<is_stl_sequential_container<SerT>::value, SerT>::type;
/* ... and many others. */
/* Serialization of float, double, long double... */
template <class Serializer, class SerializedType>
void serialize(Serializer& s, const SerializedFloating<SerializedType> &t) const {
s.Double(t);
}
/* Serialization of vector<>, dequeue<>, list<> and forward_list<> */
template <class Serializer, class SerializedType>
void serialize(Serializer& s, const SerializedSeqCntr<SerializedType> &t) const {
/* Let's assume we want to serialize them as JSON arrays: */
s.StartArray();
for(auto const& i : t) {
serialize(s, i); // ----> this fails to instantiate correctly.
}
s.EndArray();
}
/* If the previous templates could not be instantiated, check
* whether the SerializedType is a class with a proper serialize
* function:
**/
template <class Serializer, class SerializedType>
void serialize(Serializer&, SerializedType) const
{
/* Check existance of:
* void SerializedType::serialize(Serializer&) const;
**/
static_assert(has_serialize<
SerializedType,
void(Serializer&)>::value, "error message");
/* ... if it exists then we use it. */
}
};
template <class T>
class MState : public MVariable
{
T m_state;
template <class Serializer>
void serialize(Serializer& s) const {
s.Key(m_variable_name);
MVariable::serialize<Serializer, T>(s, m_state);
}
};
is_stl_sequential_container 的实现是基于this,has_serialize 的实现是从here 借用的。两者都经过检查,似乎工作正常:
MState<float> tvar0;
MState<double> tvar1;
MState<std::vector<float> > tvar2;
rapidjson::StringBuffer str_buf;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(str_buf);
writer.StartObject();
tvar0.serialize(writer); /* --> First function is used. Ok! */
tvar1.serialize(writer); /* --> First function is used. Ok! */
tvar2.serialize(writer); /* --> Second function is used, but there's
* substitution failure in the inner call.
**/
writer.EndObject();
但是,第二个函数内的递归serialize 调用无法实例化。编译器从这个开始抱怨:
In instantiation of ‘void MVariable::serialize(Serializer&, SerializedType) const
[with Serializer = rapidjson::PrettyWriter<... blah, blah, blah>;
SerializedType = float]’:
该消息继续出现静态断言错误,表明所有先前重载的模板函数在替换时都失败了,或者最后一个是最佳选择。
为什么在此处替换 float 会“失败”,而不是在我尝试序列化 tvar0 或 tvar1 时?
【问题讨论】:
标签: c++ templates serialization sfinae rapidjson