c++ - C++ 如何选择要使用的运算符重载?

标签 c++ templates operator-overloading

我正在编写一组用于自定义序列化和反序列化的类。我想我会使用 << 和 >> 运算符,因为它们通常传达了这个意思。让我们从一个用于处理写入通用流的类开始。

class Writer
{
public:
  virtual void writeBytes(const void* p, size_t n) = 0;
  template <typename T> void write(const T& v)
  {
    writeBytes(&v, sizeof(v));
  }
  template <typename T> Writer& operator<<(const T& v)
  {
    write(v);
    return *this;
  }
};

然后有一个可序列化的接口(interface),即提供它自己的序列化方法。

class Serializable
{
public:
  virtual Writer& serialize(Writer& writer) const = 0;
};

Writer& operator<<(Writer& writer, const Serializable& s)
{
  s.serialize(writer);
  return writer;
}

最后,我写了一个如何使用它的例子:一个可序列化的缓冲区。

class SerializableBuffer : public Serializable
{
public:
  SerializableBuffer() : data_(NULL), length_(0) { }
  SerializableBuffer(void* data, size_t length) : data_(data), length_(length) { }
  virtual Writer& serialize(Writer& writer) const
  {
    writer.writeBytes(data_, length_);
    return writer;
  }
private:
  void* data_;
  size_t length_;
};

所以这是有趣的部分。显然,如果我使用方法调用,它会完全按照预期的方式进行。但是使用 << 运算符显示出一些怪癖。我的第一次尝试是执行以下操作:

  unsigned char input[] = { 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0x12, 0x34 };
  SerializableBuffer sb(input, sizeof(input));

  unsigned char d[8]; 
  BufferWriter writer(buffer(d));

  writer << sb;

这失败了,因为输出缓冲区不够大。如果我加了一个printf,原来是调用了Writer类中的模板!这是更奇怪的部分,以下作品。

  unsigned char input[] = { 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0x12, 0x34 };
  SerializableBuffer sb(buffer(input));

  unsigned char d[8]; 
  BufferWriter writer(buffer(d));

  writer << (Serializable&)sb;

我猜模板引擎正在赢得后代?谁能解释这里发生了什么以及为什么?

最佳答案

它非常简单——它只是遵循重载决议规则。你有两个重载 operator <<当第一个参数是 Writer & 时可能匹配或子类:

template <typename T> Writer& Writer::operator<<(const T& v);
Writer& operator<<(Writer& writer, const Serializable& s);

当第二个参数是 SerializableBuffer 时,第一个可以完全匹配,而第二个可以与转换匹配。由于完全匹配更好,所以第一个匹配。

当第二个参数是 Serializable 时, 两者完全匹配,所以第二个更好,因为它不是模板。

如果你想让模板在参数是Serializable的子类时不匹配, 你可以使用 enable_if :

template <typename T>
std::enable_if<!std::is_base_of<Serializable, T>::value, Writer &>::type
operator<<(const T &v)

这将导致模板无法为 Serializable 的任何子类实例化。 .

关于c++ - C++ 如何选择要使用的运算符重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33106610/

相关文章:

C++梯形积分函数在不应该返回负数时返回

android - 如果不支持 EGL_NATIVE_RENDERABLE,如何通过 C++/NDK 访问 OpenGL ES 2?

c++ - MDI 子窗口大小

python - AppEngine 和 Django : including a template file

c++ - 重载大于有或没有友元的运算符

c++ - Visual C++ 输出退出得如此之快

c++ - 仅当元组中存在该类型时才将函数应用于元组元素

c++ - 重载+运算符

c++ - 类型转换运算符中的类型是否有任何限制?

c++ - 带有模板参数的部分专用模板