Skip to content

Instantly share code, notes, and snippets.

@jvranish
Created January 18, 2011 15:45
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jvranish/784615 to your computer and use it in GitHub Desktop.
Save jvranish/784615 to your computer and use it in GitHub Desktop.
Example Either type in C++
#include <stdio.h>
template <class T1, class T2>
class Either
{
bool isLeft;
union
{
T1 left;
T2 right;
};
template<class T1_, class T2_> friend Either<T1_, T2_> Left(T1_ x);
template<class T1_, class T2_> friend Either<T1_, T2_> Right(T1_ x);
public:
bool matchLeft(T1& x)
{
if (isLeft)
x = left;
return isLeft;
}
bool matchRight(T2& x)
{
if (!isLeft)
x = right;
return !isLeft;
}
};
template <class T1, class T2>
Either<T1, T2> Left(T1 x)
{
Either<T1, T2> e;
e.isLeft = true;
e.left = x;
return e;
}
template <class T1, class T2>
Either<T1, T2> Right(T2 x)
{
Either<T1, T2> e;
e.isLeft = false;
e.right = x;
return e;
}
int main(int argc, char* argv[])
{
Either<int, float> x = Left<int, float>(5);
int c;
if (x.matchLeft(c))
printf("the number is %i", c);
return 0;
}
@3noch
Copy link

3noch commented Feb 21, 2013

I wish Boost provided this. :( It has Maybe (e.g. boost::optional<T>), but not my beloved Either.

@eduardoleon
Copy link

3noch: It is called boost::variant, but it is ugly as hell.

@3noch
Copy link

3noch commented Mar 6, 2013

According to boost::variant's docs, using union like above will only support POD types.

@mloskot
Copy link

mloskot commented Jul 3, 2013

Check the last month thread on Interest in an 'either' library?

@3noch
Copy link

3noch commented Jul 17, 2013

Here's a simple version I've been using that [mildly] depends on boost: https://gist.github.com/3noch/6024523

@gonzaw
Copy link

gonzaw commented Nov 23, 2014

Shouldn't it be template<class T1_, class T2_> friend Either<T1_, T2_> Right(T2_ x); instead of template<class T1_, class T2_> friend Either<T1_, T2_> Right(T1_ x); ?

@scravy
Copy link

scravy commented Aug 29, 2018

@gonzaw I think so. And the typo is not caught in the example as it only demonstrates the left side. The class should befriend both left and right with the appropriate template arguments for left and right respectively.

@Matzz
Copy link

Matzz commented Dec 1, 2020

I'm using Arduino like chip with c++11 but no std lib or exceptions support. I end up defining sth like that:

#pragma once

template <class L, class R> 
class Either
{
    virtual bool isLeft();
    virtual bool isRight();

    virtual bool matchLeft(L& x);
    virtual bool matchRight(R& x);
};

template <class L, class R> 
class Left : public Either<L, R> {
public:
    L left;

    Left(L left): left(left) {}
    constexpr bool isLeft() { return true; }
    constexpr bool isRight() { return false; }

    bool matchLeft(L& x)
    {
        x = left;
        return true;
    }
    bool matchRight(R& x) { return false; }
};

template <class L, class R> 
class Right : public Either<L, R> {
public:
    R right;

    Right(R right): right(right) {}
    constexpr bool isLeft() { return false; }
    constexpr bool isRight() { return true; }

    bool matchLeft(L& x) { return false; }

    bool matchRight(R& x) {
        x = right;
        return true;
    }
};

I'm not native C++ dev so I would be glad for comments.

@DonaldHobson
Copy link

Are you sure you meant
template<class T1_, class T2_> friend Either<T1_, T2_> Right(T1_ x);
not
template<class T1_, class T2_> friend Either<T1_, T2_> Right(T2_ x);
?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment