1

I've got a few classes with the with a visit function like so:

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

I have a visitor like:

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

For each visitor I want to define a stream operator:

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

Is it possible to provide a single operator<< that accepts any Visitable class?

(Right now, I'm just experimenting with printing, but I actually want to implement json serialization, deserialization and perhaps equality and less-than operators.

UPDATE

I used Davids solution:

Base class for CRTP:

template <class T> struct Visitable {}; 

All visitable classes inherit from there:

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

Operators and functions are templated as so, and use a static cast to visit the class:

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; } 
1
  • 4
    I am having difficulties parsing "Is it possible do not have to implement the operator just once in a templated function" Commented Aug 14, 2012 at 13:18

2 Answers 2

1

The approach that you are taking is similar to how the boost serialization library is implemented, with the difference that in their case they are overloading operator& (binary and, not address-of) to interact with the library. Then the visitors will use a single serialize operation on the type.

Now, the problem is that I don't really understand the question:

Is it possible do not have to implement the operator just once in a templated function?

Do you mean providing a single operator<< that will take any visitor(serializer) type? If that is the question, and without going into much detail, you could try using inheritance and the CRTP to solve this. Implement the operator as a member function in a templated base of all your visitors that takes the concrete visitor as argument.

I am not too sure how that would apply to the comparison operators, while operator<< and operator>> look natural for serialization, they would be surprising for any other operation.

Sign up to request clarification or add additional context in comments.

6 Comments

So I'd have a base template class, that implements all operations/operators I want visitors to have. Thanks
@njr: Google for CRTP, it is not as simple as creating a base class, to be able to execute the code that you want you will need a bit of template hackery.
Thanks, I've got everything working, interestingly my base class' definition is empty.
Since I've got it working, should I post my code as an answer?
@njr: Post it as an answer (or if as an edit to the question, but make a clear distinction that it is an answer). The empty base... sounds a bit strange...
|
0

Do you mean you want to do something like this?

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

This will cause ambiguity of course. What you want is this:

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

I don't know if this is possible.

You can also do this:

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

and then implement a normal function:

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

but then you have a small overhead of a virtual function call.

2 Comments

The problem with this approach is that the presence of this templated overload will cause ambiguities with some of the operator<<s provided in the standard.
Yes I know, I'm just clarifying what you are trying to do. You want this template instantiated only when Visitable has implemented the visit function. I'm not clear if this can be achieved through template specialization, SFINAE, and so on. (Clearly it could be done with inheritance, you could make a base class Visitible, and then implement a normal non-templated function)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.