0

I'm new to cC++. I hope the code snippet explains well enough what I'm trying to achieve. I want a global and a element function for overloading of the < operator. In the element function the return type is bool and in the global function it is the respective type. Is this code possible to realize? (Not working right now?)

     class Foo{     
     //...
     //element function:
     bool operator<(const Foo& otherFoo){//implementation}
     }
     //global function:
     Foo& operator<(const Foo& foo1, const Foo& f2)
     {
         if (f1.operator<(f2))
            return f1;
         else;
      return f2;
      }
airborne
  • 3,664
  • 4
  • 15
  • 27
  • I'm have trouble understanding what you are asking but this might help: http://stackoverflow.com/questions/4421706/operator-overloading – NathanOliver Apr 13 '17 at 15:15
  • 2
    I'm almost afraid to ask what the ability to do this would actually *solve*. – WhozCraig Apr 13 '17 at 15:18
  • `Not working right now` - its not working because you have some obvious compile errors, you want us to fix it? – marcinj Apr 13 '17 at 15:20
  • Do you want to have generalised booleans (that's the term used in common lisp for such behavior)? Treating everything except for a special value as truth value? – Daniel Jour Apr 13 '17 at 15:30

1 Answers1

0

Is this code possible to realize?

Yes. But you really, really, really should not do it! operator< has a very concise meaning: Is the left hand side "less" (for some definition of "less") than the right hand side?

Returning the object which is actually "less" is also a reasonable function, but it should be named accordingly! Call it lesser_of or something like that.

Not working right now?

You did not include any useful error description in your question, but I highly suspect that the issue here is const correctness. You're accepting a reference to a const qualified Foo and try to call its member function operator< which is not const qualified. The simple fix: Add a const to the member function:

// member function:                 vvvvv
bool operator<(const Foo& otherFoo) const {
  // implementation                 ^^^^^
}

The supposed free (= non-member) function (which should really be called with a reasonable name, I chose lesser_of) can be implemented for all types with a corresponding member function, using a template:

template<typename L, typename R>
typename std::common_type<L,R>::type lesser_of(L&& left, R&& right) {
  using std::forward;
  // Could also use operator<(forward<L>(left), forward<R>(right)), but
  // this breaks when there's both a member function and a free
  // function available.
  if (left.operator<(forward<R>(right))) {
    return forward<L>(left);
  } else {
    return forward<R>(right);
  }
}

Note that I have no idea whether the forwarding makes any sense, nor am I sure if this could lead to dangling references.

Going a bit further, there's one kind of usage that I would consider "only just ok" if you really insist on returning "more" than a bool from operator<: In Common Lisp this is called "generalized boolean", and basically means that anything except a special nil value is considered to be "truthy". You could "port" that to C++ and use std::optional (C++17!) to convey that meaning:

template<typename L, typename R>
std::experimental::optional<L> operator<(L&& left, R&& right) {
  if (left.operator<(std::forward<R>(right))) {
    return std::forward<L>(left);
  } else {
    return std::experimental::nullopt_t{};
  }
}

This returns the left operand wrapped in a std::optional if indeed it is "less" than the right. The result can be checked for in e.g. an if (or similar "special context") because it has a (explicit) conversion member function to bool. Thus returning std::optional instead of bool won't break code that uses the comparison only where contextual conversions can be applied. The returned value can be access by dereferencing or for example the value member function.

Of course this does not allow code like Foo c = a < b;, but you could instead use Foo c = (a < b).value_or(b);.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63