为什么std :: is_same不起作用?

时间:2015-04-14 22:00:50

标签: c++ templates c++11

我的代码段是:

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);
}

我有错误:

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'

这很奇怪。我不明白为什么会发生这些错误。

3 个答案:

答案 0 :(得分:5)

此代码

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;
}

没有按你的想法行事。当函数模板serialize被实例化时,其代码必须格式正确,但事实并非如此。考虑内部发生的事情,例如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;
}

答案 1 :(得分:5)

在某些其他语言中,

if不是static if。未到达的分支仍然必须编译。

标记调度(如果您正在执行比is_same更复杂的事情(例如,接受基于is_input_stream特征的各种流),这会更有用;在使用中没有太大意义一个模板,它只接受两种类型,并且每种类型完全不同的东西):

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>());
}

或仅为serializeoutput_stream {<1}}重载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));
}

我冒昧地让serialize通过引用接受流。另外,我不认为你的阅读&#34;逻辑是正确的。您不仅泄漏了使用new分配的内存,而且我非常怀疑您是否要分配sizeof(not_pod_struct) not_pod_struct的数组。

答案 2 :(得分:1)

您还可以使用完整模板规范,并在使用除input_stream或output_stream之外的其他参数调用serialize时抛出异常。 这与原始代码非常接近。

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));
}