Reputation: 3707
My code snippet is:
namespace serialization
{
struct output_stream
{
/////
void write(const void* data, size_t size)
{
const byte_t* p = static_cast<const byte_t*>(data);
size_t old_size = buffer_.size();
buffer_.resize(old_size + size);
memcpy(buffer_.data() + old_size, p, size);
}
}
struct input_stream
{
///////
void read(void* to, size_t size)
{
assert(cur_ + size <= end_);
memcpy(to, cur_, size);
cur_ += size;
}
}
}
template <class stream_t>
void serialize(not_pod_struct& r, stream_t stream)
{
if (std::is_same<stream_t, serialization::output_stream>::value)
{
stream.write(&r, sizeof(r));
}
else if (std::is_same<stream_t, serialization::input_stream>::value)
{
not_pod_struct* buf = new not_pod_struct[sizeof(not_pod_struct)];
stream.read(buf, sizeof(not_pod_struct));
r = *buf;
}
else
{
throw std::invalid_argument("stream_t is not a stream.");
}
}
template<class T>
typename enable_if<!is_pod<T>::value, void>::type
read(input_stream & input_stream, T & non_pod_struct)
{
serialize(non_pod_struct, input_stream);
}
template<class T>
typename enable_if<!is_pod<T>::value, void>::type
write(output_stream & output_stream, T & non_pod_struct)
{
serialize(non_pod_struct, output_stream);
}
I have errors:
Error 1 error C2039: 'read' : is not a member of 'serialization::output_stream'
Error 2 error C2039: 'write' : is not a member of 'serialization::input_stream'
This is strange. I do not understand why these errors happen.
Upvotes: 1
Views: 1458
Reputation: 347
You can also use full template specification and throw an exception when serialize is called with another argument than input_stream or output_stream. This is close to your original code.
template<typename X>
void serialize(not_pod_struct & r, X & x)
{
throw std::invalid_argument("stream_t is not a stream.");
}
template<>
void serialize(not_pod_struct& r, serialization::input_stream & stream)
{
not_pod_struct* buf = new not_pod_struct[sizeof(not_pod_struct)];
stream.read(buf, sizeof(not_pod_struct));
r = *buf;
}
template<>
void serialize(not_pod_struct& r, serialization::output_stream & stream)
{
stream.write(&r, sizeof(r));
}
Upvotes: 1
Reputation: 137330
if
is not static if
in certain other languages. A branch that is not reached still must compile.
Tag dispatch (this is more useful if you are doing something more complicated than is_same
(e.g., accept various streams based on an is_input_stream
trait); there's not much point in using a template that only accepts two types and do completely different things with each):
template <class stream_t>
void serialize(not_pod_struct& r, stream_t & stream,
std::true_type /* is_input */, std::false_type /* is_output */)
{
not_pod_struct* buf = new not_pod_struct[sizeof(not_pod_struct)];
stream.read(buf, sizeof(not_pod_struct));
r = *buf;
}
template <class stream_t>
void serialize(not_pod_struct& r, stream_t & stream,
std::false_type /* is_input */, std::true_type /* is_output */)
{
stream.write(&r, sizeof(r));
}
template <class stream_t>
void serialize(not_pod_struct& r, stream_t & stream)
{
serialize(r, stream, std::is_same<stream_t, serialization::input_stream>(),
std::is_same<stream_t, serialization::output_stream>());
}
Or just overload serialize
for output_stream
and input_stream
:
void serialize(not_pod_struct& r, serialization::input_stream & stream)
{
not_pod_struct* buf = new not_pod_struct[sizeof(not_pod_struct)];
stream.read(buf, sizeof(not_pod_struct));
r = *buf;
}
void serialize(not_pod_struct& r, serialization::output_stream & stream)
{
stream.write(&r, sizeof(r));
}
I took the liberty of having serialize
accept the stream by reference. Also, I don't think your "read" logic is correct. Not only do you leak the memory allocated with new
, I'm extremely doubtful that you meant to allocate an array of sizeof(not_pod_struct)
not_pod_struct
s.
Upvotes: 5
Reputation: 41301
This code
if (std::is_same<stream_t, serialization::output_stream>::value)
{
stream.write(&r, sizeof(r));
}
else if (std::is_same<stream_t, serialization::input_stream>::value)
{
not_pod_struct* buf = new not_pod_struct[sizeof(not_pod_struct)];
stream.read(buf, sizeof(not_pod_struct));
r = *buf;
}
is not doing what you think. When the function template serialize
is instantiated, its code must be well-formed, but it is not. Consider what happens inside e.g serialize<output_stream>
:
if (true)
{
stream.write(&r, sizeof(r));
}
else if (false)
{
// This branch never executes, but this doesn't mean it's not compiled!
not_pod_struct* buf = new not_pod_struct[sizeof(not_pod_struct)];
// And output_stream doesn't have read() method.
stream.read(buf, sizeof(not_pod_struct));
r = *buf;
}
Upvotes: 5