Return empty std::pair from function

16,844

Solution 1

Generally speaking an empty pair doesn't even make sense. Afterall a pair is per definition a container containing two objects.

You could however make something like an empty pair using Boost.Optional. Then you would either use a boost::optional<std::pair<...>> giving you the option of returning either a pair or an empty state or use std::pair<boost::optional<...>, boost::optional<...>> for a pair where either object could be empty.

Solution 2

You can returns pointer... Or use boost::optional<T>. Optional will be better...

boost::optional<std::pair<int, int> > MyClass::someFunction()
{
    return boost::optional<std::pair<int, int> >();
}

void f(const MyClass& f)
{
    boost::optional<std::pair<int, int> > ret = f.someFunction();
    if (!ret) // empty
    {
        ...
    }
}

Solution 3

The answer to your questions is easily explained by considering the way the C++ compiler generates code in this case.

The std::pair<int, int> is returned-by-value.

Since MyClass::someFunction() is returning an object by value, the sequence of events is as follows:

  • The calling function reserves space on the stack for a std::pair<int, int>
  • The MyClass::someFunction() is called
  • The right hand side of the return statement is a assignment to the location reserved on the stack earlier. There is an implicit construction of a std::pair<int, int> taking place.

Thus returning a NULL pointer is impossible.

Solution 4

It wouldn't take much to create your own "optional pair" (similar to boost::optional<std::pair<…>>, but with a different interface), e.g.:

template <typename T1, typename T2> struct OptPair : std::pair<T1, T2>
{
  typedef std::pair<T1, T2> base_t;
  bool contains;
  OptPair() : contains(true) {}
  explicit OptPair(bool x) : contains(x) {}
  OptPair(const T1& x, const T2& y) : base_t(x, y), contains(true) {}
  template <class U, class V>
  OptPair(const std::pair<U,V> &p) : base_t(p), contains(true) {}
  template <class U, class V> OptPair(const OptPair<U,V> &p) : base_t(p), contains(p.contains) {}
  // No need to define operator=, as the default will construct an OptPair<T1, T2>
  // if necessary, then copy members into *this.
};

template <typename T1, typename T2>
OptPair<T1, T2> makeOptPair() { return OptPair<T1, T2>(); }

template <typename T1, typename T2>
OptPair<T1, T2> makeOptPair(const T1 &x, const T2 &y) {
  OptPair<T1, T2> p(true);
  p.first = x;
  p.second = y;
  return p;
}

template <typename OS, typename T1, typename T2>
OS &operator<<(OS &os, const OptPair<T1, T2>& p) {
  os << "<OptPair: ";
  if (p.contains) os << p.first << ", " << p.second;
  else os << "empty";
  os << ">";
  return os;
}

Then you can use it just like std::pair (and even use it interchangeably with std::pair, assigning values back and forth), but with the added ability to pass an "empty" value back like this:

OptPair<int, int> someFunction()
{
   ...
   return OptPair<int, int>(false); 
}

You have to make sure to check the result before using it, like this:

void doStuffWithPair(std::pair<int, int>);
void doStuffWithEmpty();
...
OptPair<int, int> ret = someFunction();
if (ret.contains) doStuffWithPair(ret);
else doStuffWithEmpty();

Solution 5

A pair, by definition, has 2 elements. It cannot have none.

You need something like boost::optional<std::pair<T1,T2>>. Then you can choose to have a pair or not. You can find documentation for boost::optional here.

Share:
16,844
Admin
Author by

Admin

Updated on July 27, 2022

Comments

  • Admin
    Admin almost 2 years

    Is it possible to return an empty pair from a function? Meaning, follow the rules of the function prototype, but do not have any elements in the pair (e.g. NULL). Understanding that a pair simply exists so I don't know if this is conceptually possible. I have a need to return a pair that is NULL or empty, if that makes any sense.

    For example,

    pair<int, int> MyClass::someFunction()
    {
    
       // do something that means we need to return an empty pair
       return NULL; // <--- this does not work obviously
    }
    

    Unfortunately, boost is not a possibility for me.