At work, I ran into a situation where the best type to describe the result returned from a function would be std::variant<uint64_t, uint64_t>
- of course, this isn't valid C++, because you can't have two variants of the same type. I could represent this as a std::pair<bool, uint64_t>
, or where the first element of the pair is an enum, but this is a special case; a std::variant<uint64_t, uint64_t, bool>
isn't so neatly representable, and my functional programming background really made me want Either
- so I went to try to implement it, using the Visitor pattern as I have been able to do in other languages without native support for sum types:
template <typename A, typename B, typename C>
class EitherVisitor {
virtual C onLeft(const A& left) = 0;
virtual C onRight(const B& right) = 0;
};
template <typename A, typename B>
class Either {
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) = 0;
};
template <typename A, typename B>
class Left: Either<A, B> {
private:
A value;
public:
Left(const A& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onLeft(value);
}
};
template <typename A, typename B>
class Right: Either<A, B> {
private:
B value;
public:
Right(const B& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onRight(value);
}
};
C++ rejects this, because the template method Accept
cannot be virtual. Is there a workaround to this limitation, that would allow me to correctly represent the fundamental sum type in terms of its f-algebra and catamorphism?