Advice of generic interface

Discussion in 'C++' started by nicola, May 5, 2010.

  1. nicola

    nicola Guest

    Hi,
    I have a generic interface for intervals, which is defined in terms of
    two global functions leftPoint() and rightPoint(). Many other
    functions and operators are defined in terms of those two in a
    standard way, so that, in principle, I only need to provide a
    definition for leftPoint() and rightPoint() to adapt a specific data
    type to an interval interface. But providing generic definitions for
    the operators calls for trouble (unwanted instantiations and broken
    name lookup). Is there any viable alternative to overloading all the
    functions and operators for each data type (duplicating much of the
    code)? Or, is there anything better than the following?

    namespace A {
    // Generic interface
    template <typename I> point_type leftPoint(I const& i);
    template <typename I> point_type rightPoint(I const& i);
    template <typename I> operator<(I const& i, I const& j); // “too
    generic”
    // […]
    // Specializations
    int leftPoint(std::pair<int,int>); int
    rightPoint(std::pair<int,int>);
    float leftPoint(MyFloatInterval); float rightPoint(MyFloatInterval);
    // […]
    }
     
    nicola, May 5, 2010
    #1
    1. Advertising

  2. nicola

    Jonathan Lee Guest

    On May 5, 3:43 pm, nicola <> wrote:
    > But providing generic definitions for
    > the operators calls for trouble (unwanted instantiations and broken
    > name lookup). Is there any viable alternative to overloading all the
    > functions and operators for each data type (duplicating much of the
    > code)? Or, is there anything better than the following?


    I'm not _exactly_ sure what you're trying to do, but maybe
    boost::enable_if will allow you to nix templates that you
    don't want ("too generic").

    --Jonathan
     
    Jonathan Lee, May 5, 2010
    #2
    1. Advertising

  3. nicola

    John H. Guest

    nicola wrote:
    > Hi,
    > I have a generic interface for intervals, which is defined in terms of
    > two global functions leftPoint() and rightPoint(). Many other
    > functions and operators are defined in terms of those two in a
    > standard way, so that, in principle, I only need to provide a
    > definition for leftPoint() and rightPoint() to adapt a specific data
    > type to an interval interface. But providing generic definitions for
    > the operators calls for trouble (unwanted instantiations and broken
    > name lookup). Is there any viable alternative to overloading all the
    > functions and operators for each data type (duplicating much of the
    > code)?


    I can't quite tell what your needs are, but maybe something like this:

    template <typename T>
    class Range
    {
    public:
    Range(T left, T right) : left(left), right(right) { }
    bool operator<(Range const & r) const
    {
    return left<r.left && right<r.right;
    }
    // other common methods go here
    private:
    T left;
    T right;
    };

    You could then extend this to be initialized with certain data types
    (e.g. std::pair<int,int>) by either:
    Adding constructors to the class:

    template <typename T>
    class Range
    {
    public:
    Range(T left, T right) : left(left), right(right) { }
    Range(std::pair<int,int> vals) : left(vals.first),
    right(vals.second) {} // added
    bool operator<(Range const & r) const
    {
    return left<r.left && right<r.right;
    }
    // other common methods go here
    private:
    T left;
    T right;
    };

    or by creating subclasses:

    class IntRange : public Range<int>
    {
    public:
    IntRange(std::pair<int,int> vals) : Range<int>(vals.first,
    val.second) { }
    };
     
    John H., May 6, 2010
    #3
  4. nicola

    nicola Guest

    On 5 Mag, 22:03, Jonathan Lee <> wrote:
    > On May 5, 3:43 pm, nicola <> wrote:
    >
    > I'm not _exactly_ sure what you're trying to do, but maybe
    > boost::enable_if will allow you to nix templates that you
    > don't want ("too generic").


    Thanks for the suggestion, boost::enable_if seems really useful.
    But let me restate my questions in different and more general terms:

    1) is it bad practice or are there any drawbacks in defining a fully
    generic operator within a namespace? E.g.:

    namespace A {
    template <typename T>
    bool operator==(T const& lhs, T const& rhs) {
    // Something specific to definitions in A
    }
    }

    In all the code I've seen, operators are always overloaded for
    specific types (or parametrized types, e.g., MyArray<T>), but never
    for a fully generic type T.

    2) Sutter and Alexandrescu suggest in C++ Coding Standards to avoid
    putting a type into the same namespace as a templated function or
    operator (although the STL does that). Consider the following:

    namespace A {
    template <typename T>
    T f(T const&);

    template <typename T>
    void g(T const& x) {
    /* … */ f(x);
    }
    template <typename T>
    ostream& operator<<(ostream& os, T const& x) {
    os << f(x);
    return os;
    }
    // Specializations
    struct X { /* … */ };
    T f(X&) { /* … */ }
    }

    The rationale with the code above is to allow one to use f(), g() and
    operator<< with different types by overloading only f() (assuming that
    the implementation of g() and operator<< is common to many types). Do
    Sutter and Alexandrescu imply that there may be problems with this
    code? Or that g() and operator<< shouldn't be generic but there should
    rather be a definition for each concrete type X?

    3) According to Sutter's Interface Principle, should g() and
    operator<< be considered “part of X” or not? (They do not “mention” X
    as they are generic.)
     
    nicola, May 6, 2010
    #4
  5. nicola

    Jonathan Lee Guest

    On May 6, 4:58 pm, nicola <> wrote:
    > 1) is it bad practice or are there any drawbacks in defining a fully
    > generic operator within a namespace? E.g.:


    What happens if someone puts a class in A that doesn't
    have a meaningful definition for operator== ? Like a
    socket class or something.

    If your answer happens to be "Well, nobody's gonna
    add things to A" then I think _that_ would be bad
    practice.

    Also, how'd you even come up with a namespace-wide
    definition for 'equality'? If there are particular
    characteristic classes must meet to be in A, and
    that then validate the use of operator==, then I'd
    refer you again to enable_if. Or SFINAE in general.

    > [...] avoid putting a type into the same namespace
    > as a templated function or operator


    *shrugs* Don't know about that. I've never had it be
    a problem, but then I guess I don't actually do it
    very much either.

    > The rationale with the code above is to allow one to use f(), g() and
    > operator<< with different types by overloading only f()


    See.. this I would use SFINAE for. For example, if f()
    is some kind of toString() function, then I'd simply
    make it a member of X. The operator<< template would just
    read

    os << x.toString();

    > 3) According to Sutter's Interface Principle, should g() and
    > operator<< be considered “part of X” or not? (They do not “mention” X
    > as they are generic.)


    But once the template is instantiated then, yeah, it does
    mention X. IMO that makes it "part of X"

    --Jonathan
     
    Jonathan Lee, May 6, 2010
    #5
  6. nicola

    nicola Guest

    On 7 Mag, 00:02, Jonathan Lee <> wrote:
    >
    > If your answer happens to be "Well, nobody's gonna
    > add things to A" then I think _that_ would be bad
    > practice.


    Well, nobody is supposed to add things to namespace std, I think :)
    Anyway, you've made a good point and, as others have also said,
    enable_if or SFINAE is appropriate.

    > […]
    > > The rationale with the code above is to allow one to use f(), g() and
    > > operator<< with different types by overloading only f()

    >
    > See.. this I would use SFINAE for. For example, if f()
    > is some kind of toString() function, then I'd simply
    > make it a member of X. The operator<< template would just
    > read
    >
    >   os << x.toString();


    What if X is not a class? You would have to overload all the functions
    and operators… The idea behind the approach I was trying is to reduce
    to amount of code you would have to write for a new arbitrary type. My
    goal was to adapt unrelated types to my interface without changing
    them or wrapping them. But now I realize that I was doing something
    pretty silly, which can be summarized as:

    namespace A {
    template <typename T> T f(T const&);
    template <typename T> void g(T const&) { /* … */ f(x); }
    template <typename T> ostream& operator<<(ostream& os, T const& x);

    typedef std::pair<int,int> Y;
    Y f(Y const& y) { /* … */ }
    }

    Then, A::g(A::Y()) would be fine (with a forward declaration), but for
    operators (e.g., std::cout << A::Y()) there's no hope. Besides, this
    has nothing to do with the genericity of the functions and operators.
    It seems like using a base class (as another poster has suggested)
    would be much easier… A “generic is-a” seems far less simple without
    further support, Is boost::enable_if going to become part of the
    standard?
     
    nicola, May 7, 2010
    #6
  7. nicola <> writes:
    > Is boost::enable_if going to become part of the standard?


    The next Standard, C++0x as it is currently named, is at Final Committee
    Draft. This is available online at
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdf. If
    you search within this document for "[meta.type.synop]" (without the
    quotes), you can see that enable_if will indeed be available from the
    <type_traits> header. Indeed your implementation may already have this
    available, if it offers C++0x support, as well (very probably) via an
    earlier implementation of `tr1', if it has that. (Don't quote me on
    this, but I have the idea in my mind that, if tr1 is present for your
    implementation, then Boost merely makes use of that in place of its own
    implementation. Maybe.)

    What compiler implementation are you using, BTW?

    Regards

    Paul Bibbings
     
    Paul Bibbings, May 7, 2010
    #7
  8. nicola

    nicola Guest

    On 7 Mag, 13:44, Paul Bibbings <> wrote:
    > nicola <> writes:
    > > Is boost::enable_if going to become part of the standard?

    >
    > […] you can see that enable_if will indeed be available from the
    > <type_traits> header.


    Thanks for the pointer.

    >  Indeed your implementation may already have this
    > available


    My compiler (g++ 4.2.1) has a tr1/type_traits header, but no enable_if
    definition inside. But I've started to use boost::enable_if and that
    does exactly what I want.

    Nicola
     
    nicola, May 7, 2010
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?U3Rld2FydCBSb2dlcnM=?=

    Generic/Adoptive User Interface Design

    =?Utf-8?B?U3Rld2FydCBSb2dlcnM=?=, Apr 6, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    382
    =?Utf-8?B?U3Rld2FydCBSb2dlcnM=?=
    Apr 6, 2005
  2. Murat Tasan
    Replies:
    1
    Views:
    8,051
    Chaitanya
    Feb 3, 2009
  3. HK
    Replies:
    1
    Views:
    305
    Stefan Schulz
    Jul 15, 2005
  4. Replies:
    2
    Views:
    437
  5. minlearn
    Replies:
    2
    Views:
    456
    red floyd
    Mar 13, 2009
Loading...

Share This Page