
AMDG On 06/24/2012 02:53 PM, Pyry Jahkola wrote:
On 2012-06-24 18:34:13 +0000, Steven Watanabe said:
On 06/24/2012 08:13 AM, Dave Abrahams wrote:
Very interesting. Does either approach support operator overloading?
Yes. I put quite a bit of effort into making sure that operator overloads would work correctly.
I started the work on operator overloading, as you might guess when seeing the file
include/poly/operators.hpp (names in this file will definitely change)
I didn't get so far that poly::interface would actually recognize these callables and create the corresponding operators for itself, but that sure is possible.
If you have to create special cases for these in the core library, you're doing it wrong.
More importantly, I'm still kind of missing the point of why the feature of operator overloading is really needed. In essence: How should binary operators behave? Steven's TypeErasure defines binary operators such that only when the wrapped types of a and b are the same, can you sum them up: "a + b".
But where would you use this kind of an "any", where only some of the instances can be added up, and others cause undefined behavior? Wouldn't you actually do the addition on the side where you know the types, and not on the type-erased side?
Binary operators like this require you to have a coherent set of objects. You can't just take two random objects from two different sources and combine them. There are also a few special cases where binary operators can have a reasonable default behavior when the types don't match. For example, equality_comparable<> and less_than_comparable<> can test the stored /types/ first before testing the value.
Do we really have a real world use case that would prompt us to implement features like operator overloading?
any_iterator. Also, you're confusing two separate issues. Operator overloading is a separate issue from binary methods. Some operators, like ostreamable<> or incrementable<>, would normally only take one any argument.
* * *
Before releasing more worms from the can of type-erased operators, I must confess that I know still too little about the possible uses for type erasure / expression problem / what you name it. What I propose is we should look into how e.g. Haskell and Clojure programmers use their type classes and protocols.
For one thing, I could only think of few examples where the interface would have mutating functions. (Anybody care to throw in more examples?)
More typical use cases (that I could think of) are functions which read the wrapped type (as const reference), and then either (1) return a value, or (2) cause a side effect:
std::string(to_html_, self const &); // (1) "pure" function void(print_, self const &, std::ostream &); // (2) side effect
Maybe if the whole interface is about wrapping some sort of computation or side effect, it might make sense to have some non-const functions too:
using progress = interface< std::size_t(total_progress_, self const &), std::size_t(current_progress_, self const &), void(run_for_, self &, std::chrono::microseconds)>;
Or maybe it's modeling a kind of a container and you can insert items into it:
using container = interface< void(insert_, self &, std::size_t, content), void(remove_, self &, std::size_t), content &(at_, self &, std::size_t), content const &(at_, self const &)>;
In Christ, Steven Watanabe