On Aug 21, 2008, at 3:48 AM, Daniel Krügler wrote:
Daryle Walker wrote: [SNIP]
I don't know if what I'm going to say was what David was thinking of, but... If a predicate function object has several "operator ()" overloads, they should be conceptually identical. Ideally, they should be "const" member functions that depend only on the values of the inputs and any internal state data members. Even without that, your predicate class should represent ONE kind of evaluation criteria to pass judgement on. Your nightmare predicate would have to have all the "operator ()" inconsistent with each other, i.e. differing criteria. That would make it useless, considering you can't choose which overload you get in normal use. You can choose a specific version with Stupid C++ Tricks involving casting the inputs and/or the member function, but that won't help with generic (template- based) code. Testing operations that aren't the same shouldn't be part of the same predicate class.
Thank you very much for your reply and apologies for my late response!
My main concern was that the standard should not be too intrusive, but your arguments made me reflect again on this. Users should easily be able to separate their predicate "bundle", if their see strong need for such a bundle, e.g. instead of
struct S { bool (*scmp)(const char*, const char*); explicit S(streq_t sc = ...) : scmp(sc) {} // Stateless predicate: bool operator()(int a, int b) const { return a == b; } ... // other stateless predicates // Statefull predicate: bool operator()(const char* a, const char* b) const { return scmp(a, b); } };
they could (and probably should) write:
struct SPure { // Stateless predicate: bool operator()(int a, int b) const { return a == b; } ... // other stateless predicates };
struct S : SPure { bool (*scmp)(const char*, const char*); explicit S(streq_t sc = ...) : scmp(sc) {} // Statefull predicate(s): bool operator()(const char* a, const char* b) const { return scmp(a, b); } };
Inheritance is neither required nor usually wanted, but if some-one *needs* this bundle (because of external requirements) she can realize this, if she wants that.
You may have missed something. The state-fulness or statelessness of a predicate is _irrelevant_ to my point, which was that all the comparison overloads should have the same effects! Having your "S" predicate be a root class or divided with a "SPure" base class doesn't matter. Your integer and string comparisons are probably not testing the same concept, so they shouldn't be together, no matter what C++ skills you use to compose them. struct real_part_negative { bool operator ()( int x ) const { return x < 0; } bool operator ()( unsigned x ) const { return false; } bool operator ()( float x ) const { return x < 0.0; } template < typename T > bool operator ()( complex<T> const &x ) const { return x.real < static_cast<T>(0); } }; All these overloads represent the same concept, so it's a consistent predicate. This is important for generic code, where you can't pick which overload is used. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com