1

我有一些带有访问功能的类,如下所示:

struct Person {
   std::string name;
   unsigned age;

  template<class Visitor>
  void visit(Visitor& c)
  {
      c("name", name);
      c("age", age);
  }

  template<class Visitor>
  void visit(Visitor& c) const
  {
      c("name", name);
      c("age", age);
  }
};

我有一个访客,例如:

struct PrintVisitor
{
    PrintVisitor(std::ostream& stream)
        : m_stream(stream)
    {}

    template<class T>
    void operator()(const std::string& name, const T& v)
    {
        m_stream << name << ": " << v << std::endl;
    }

private:
    std::ostream& m_stream;
};

对于每个访问者,我想定义一个流操作符:

std::ostream& operator<<(std::ostream& stream, const Person& p)
{
    PrintVisitor printer(stream);
    p.visit(printer);
    return stream;
}

是否可以提供一个接受任何 Visitable 类的 operator<<?

(现在,我只是在尝试打印,但我实际上想实现 json 序列化、反序列化,也许还有相等和小于运算符。

更新

我使用大卫解决方案:

CRTP 的基类:

template <class T>
struct Visitable {};

所有可访问的类都从那里继承:

struct Person : Visitable<Person> { ... }

运算符和函数是这样模板化的,并使用静态转换来访问类:

template<class T> 
std::ostream& operator<<(std::ostream& stream, const Visitable<T>& p) 
{ 
    PrintVisitor printer(stream); 
    static_cast<const T&>(p).visit(printer); 
    return stream; 
}
4

2 回答 2

1

您采用的方法类似于 boost 序列化库的实现方式,不同之处在于在它们的情况下它们是重载operator&(二进制而不是地址)以与库交互。然后访问者将对该类型使用单个serialize操作。

现在,问题是我不太明白这个问题:

是否有可能不必在模板函数中只实现一次运算符?

你的意思是提供一个operator<<可以接受任何访问者(序列化器)类型的单曲吗?如果这是问题所在,并且无需详细说明,您可以尝试使用继承和 CRTP 来解决此问题。将运算符实现为所有访问者的模板库中的成员函数,该模板将具体访问者作为参数。

我不太确定这将如何应用于比较运算符,虽然对于序列operator<<operator>>来说看起来很自然,但对于任何其他操作来说它们都会令人惊讶。

于 2012-08-14T13:32:38.677 回答
0

你的意思是你想做这样的事情吗?

template<class Visitable>
std::ostream& operator<<(std::ostream& stream, const Visitable& v)
{
    PrintVisitor printer(stream);
    v.visit(printer);
    return stream;
}

这当然会引起歧义。你想要的是这样的:

template<class Visitable implements visit>
std::ostream& operator<<(std::ostream& stream, const Visitable& v)
{
    PrintVisitor printer(stream);
    v.visit(printer);
    return stream;
}

我不知道这是否可能。

你也可以这样做:

class Visitable { ... }
class Person : public Visitable { ... }

然后实现一个正常的功能:

std::ostream& operator<<(std::ostream& stream, const Visitable& v)

但是你有一个虚函数调用的小开销。

于 2012-08-14T13:41:19.007 回答