Making a C++ Either class based on Haskell's?

Started by
0 comments, last by GorbGorb 11 years, 7 months ago
Hi guys,

I'm trying to play around in C++ a bit by making an Either class ala Haskell's. I have the basics working, but I want to be able to call a single "value()" member function of the Either class instead of calling first() when the first value is available and second() when the second value is available. Any hints on how to get that working? So far I have the following:


template<class First, class Second>
class Either
{
public:
template<class T>
Either<First, Second>& operator=(Either<T, Empty> &either) {
first_ = either.value();
hasFirst_ = true;
return *this;
}
template<class T>
Either<First, Second>& operator=(Either<Empty, T> &either) {
second_ = either.value();
hasFirst_ = false;
return *this;
}
bool hasFirst() const { return hasFirst_; }
bool hasSecond() const { return !hasFirst_; }
const First& first() const { return first_; }
const Second& second() const { return second_; }
private:
union {
First first_;
Second second_;
};
bool hasFirst_;
};
template<class First>
class Either<First, Empty>
{
public:
Either(const First &first)
: first_(first)
{}
bool hasFirst() const { return true; }
bool hasSecond() const { return false; }
const First& value() const { return first_; }
private:
First first_;
};
template<class Second>
class Either<Empty, Second>
{
public:
Either(const Second &second)
: second_(second)
{}
bool hasFirst() const { return false; }
bool hasSecond() const { return true; }
const Second& value() const { return second_; }
private:
Second second_;
};
template<class First>
Either<First, Empty> makeEitherFirst(const First &first) {
return Either<First, Empty>(first);
}
template<class Second>
Either<Empty, Second> makeEitherSecond(const Second &second) {
return Either<Empty, Second>(second);
}


Also I've noticed perfect forwarding features of c++ 11 now, would it be possible to incorporate that in the operator = members of the Either template above. Maybe something like first_ = std::forward(either.value()). But that would require the parameters for the oepartor =() to take && values? I tried doing that but then I had to make the members && values as well, which meant I need to have appropriate default constructors.

Anyway to avoid that?

Currently this is my test code:

Seed::Either<int, float> result;
result = Seed::makeEitherFirst(3);
std::cout << result.first() << std::endl; // want this to be result.value() instead
result = Seed::makeEitherSecond(4.0);
std::cout << result.second() << std::endl; // want this to be result.value() instead


Thanks for any help!
[size=2]aliak.net
Advertisement

template<class First, class Second>
class Either
{
public:
template<class T>
Either<First, Second>& operator=(Either<T, Empty> either) {
first_ = std::move( either.value() );
hasFirst_ = true;
return *this;
}
template<class T>
Either<First, Second>& operator=(Either<Empty, T> either) {
second_ = std::move( either.value() );
hasFirst_ = false;
return *this;
}
bool hasFirst() const { return hasFirst_; }
bool hasSecond() const { return !hasFirst_; }
const First& first() const { return first_; }
const Second& second() const { return second_; }
private:
union {
First first_;
Second second_;
};
bool hasFirst_;
};

This will eliminate unnecessary copies. Look at boost::variant, it does something similar.

This topic is closed to new replies.

Advertisement