Can I overload operator<< using a template?

Discussion in 'C++' started by fungus, Jan 5, 2007.

  1. fungus

    fungus Guest

    I have some classes which have a "writeTo()" function
    but no operator<<. I want to fix it so that they
    all have an operator<< (for consistency).

    Can I do something like this:

    template <class T>
    DataDest& operator<<(DataDest& d, const T& t)
    {
    t.writeTo(d);
    return d;
    }

    I tried the above but I get errors like "no operator
    found which takes a right-hand operand of type XXX".

    Do I need to write all the operator<< and operator>>
    functions by hand?



    Also, a peeve: Why can't the compiler write operator==
    and operator< for me automatically? I have some structs
    with about 50 members in them (mostly float values) and
    to write/maintain operator==/operator< functions for
    them is a pain (not to mention bug-prone).

    I'm sure the compiler could do this for me automatically
    in exactly the same way that it generates operator= and
    copy constructors.

    Is there a good reason why this wasn't done? Something
    I'm missing...?


    --
    <\___/>
    / O O \
    \_____/ FTB. For email, remove my socks.


    We’re judging how a candidate will handle a nuclear
    crisis by how well his staff creates campaign ads.
    It’s a completely nonsensical process.
    fungus, Jan 5, 2007
    #1
    1. Advertising

  2. fungus

    Ondra Holub Guest

    fungus napsal:
    > I have some classes which have a "writeTo()" function
    > but no operator<<. I want to fix it so that they
    > all have an operator<< (for consistency).
    >
    > Can I do something like this:
    >
    > template <class T>
    > DataDest& operator<<(DataDest& d, const T& t)
    > {
    > t.writeTo(d);
    > return d;
    > }
    >
    > I tried the above but I get errors like "no operator
    > found which takes a right-hand operand of type XXX".
    >
    > Do I need to write all the operator<< and operator>>
    > functions by hand?
    >

    It should work with template:

    #include <iostream>
    #include <string>

    class A
    {
    public:
    A(int data1 = 0, int data2 = 0)
    : data1_(data1),
    data2_(data2)
    {
    }

    void writeTo(std::eek:stream& os) const
    {
    os << '[' << data1_ << ';' << data2_ << ']';
    }

    private:
    int data1_;
    int data2_;
    };

    template<typename T, typename S>
    S& operator<<(S& d, const T& t)
    {
    t.writeTo(d);
    return d;
    }

    int main(int argc,char **argv)
    {
    A a1(3, 5);
    A a2(-1, 12);
    std::string some_text(" <--> ");

    std::cout << a1 << some_text << a2 << '\n';
    }

    > Also, a peeve: Why can't the compiler write operator==
    > and operator< for me automatically? I have some structs
    > with about 50 members in them (mostly float values) and
    > to write/maintain operator==/operator< functions for
    > them is a pain (not to mention bug-prone).
    >
    > I'm sure the compiler could do this for me automatically
    > in exactly the same way that it generates operator= and
    > copy constructors.


    Well, it could do it, but it does not. it is designed this way, so take
    it as it is.
    Ondra Holub, Jan 5, 2007
    #2
    1. Advertising

  3. fungus

    Rolf Magnus Guest

    fungus wrote:

    > I have some classes which have a "writeTo()" function
    > but no operator<<. I want to fix it so that they
    > all have an operator<< (for consistency).
    >
    > Can I do something like this:
    >
    > template <class T>
    > DataDest& operator<<(DataDest& d, const T& t)
    > {
    > t.writeTo(d);
    > return d;
    > }
    >
    > I tried the above but I get errors like "no operator
    > found which takes a right-hand operand of type XXX".


    That should work. Your code is a bit short, so it's hard to tell why it
    wouldn't. It's better to show a minimal, but complete program that exhibits
    the observed behavior. The following program does compile without error
    here:

    class DataDest
    {
    };

    class MyClass
    {
    public:
    void writeTo(DataDest& d) const {}
    };

    template <class T>
    DataDest& operator<<(DataDest& d, const T& t)
    {
    t.writeTo(d);
    return d;
    }

    int main()
    {
    MyClass x;
    DataDest d;
    d << x;
    }

    > Do I need to write all the operator<< and operator>>
    > functions by hand?


    The template should be fine.

    > Also, a peeve: Why can't the compiler write operator==
    > and operator< for me automatically? I have some structs
    > with about 50 members in them (mostly float values) and
    > to write/maintain operator==/operator< functions for
    > them is a pain (not to mention bug-prone).
    >
    > I'm sure the compiler could do this for me automatically
    > in exactly the same way that it generates operator= and
    > copy constructors.
    >
    > Is there a good reason why this wasn't done? Something
    > I'm missing...?


    I think that's more of a question for comp.std.c++. That newsgroup deals
    more with the why than the how. Here, we just accept the C++ language as it
    is. ;-)
    Rolf Magnus, Jan 5, 2007
    #3
  4. fungus

    Noah Roberts Guest

    fungus wrote:

    > Also, a peeve: Why can't the compiler write operator==
    > and operator< for me automatically? I have some structs
    > with about 50 members in them (mostly float values) and
    > to write/maintain operator==/operator< functions for
    > them is a pain (not to mention bug-prone).


    Yep, that is a common problem with large, primitive obsessed objects.
    You need to rethink your design here and group your data better.

    If you want a language that will make your design mistakes easier to
    work with you've come to the wrong place. Luckily this one isn't too
    hard to fix though if you have a bunch of places where this data is
    accessed directly you're going to be there for a while.
    Noah Roberts, Jan 5, 2007
    #4
  5. fungus

    mlimber Guest

    Noah Roberts wrote:
    > fungus wrote:
    >
    > > Also, a peeve: Why can't the compiler write operator==
    > > and operator< for me automatically? I have some structs
    > > with about 50 members in them (mostly float values) and
    > > to write/maintain operator==/operator< functions for
    > > them is a pain (not to mention bug-prone).

    >
    > Yep, that is a common problem with large, primitive obsessed objects.
    > You need to rethink your design here and group your data better.


    Besides, what is the compiler supposed to do with pointer members?
    Should it compare values or pointed-to-addresses? If values, what
    should it do if one or both pointers is null? What if a pointer is
    simply uninitialized? (Answer: you've got a very subtle, hard-to-find
    bug on your hands because it's hidden in implicit code.)

    Cheers! --M
    mlimber, Jan 5, 2007
    #5

  6. > Also, a peeve: Why can't the compiler write operator==
    > and operator< for me automatically? I have some structs
    > with about 50 members in them (mostly float values) and
    > to write/maintain operator==/operator< functions for
    > them is a pain (not to mention bug-prone).
    >
    > I'm sure the compiler could do this for me automatically
    > in exactly the same way that it generates operator= and
    > copy constructors.
    >
    > Is there a good reason why this wasn't done? Something
    > I'm missing...?


    Concerning operator<:

    struct foo {
    std::string employee_name;
    Date date_hired;
    // ...
    };

    foo employers[2]=//...

    if(employers[0]>employers[1]) {
    // how does the compiler know whether to
    // compare by employee_name or by date_hired?
    }

    HTH,
    - J.
    Jacek Dziedzic, Jan 5, 2007
    #6
  7. fungus

    Rolf Magnus Guest

    mlimber wrote:

    > Noah Roberts wrote:
    >> fungus wrote:
    >>
    >> > Also, a peeve: Why can't the compiler write operator==
    >> > and operator< for me automatically? I have some structs
    >> > with about 50 members in them (mostly float values) and
    >> > to write/maintain operator==/operator< functions for
    >> > them is a pain (not to mention bug-prone).


    I can see that it could be useful to have an auto-generated operator==, but
    how would the compiler generate operator<? When is an object 'less' than
    another? If all members are 'less'? If one member is 'less'? Which one
    then? Or should it do a lexographical comparison? Which order should it use
    in that case?

    >> Yep, that is a common problem with large, primitive obsessed objects.
    >> You need to rethink your design here and group your data better.

    >
    > Besides, what is the compiler supposed to do with pointer members?
    > Should it compare values or pointed-to-addresses?


    It should compare the member's value, and since the member is a pointer,
    that means the address. The language should never implicitly dereference a
    pointer.

    > If values, what should it do if one or both pointers is null? What if a
    > pointer is simply uninitialized? (Answer: you've got a very subtle,
    > hard-to-find bug on your hands because it's hidden in implicit code.)


    How does that differ from the assignment operator, which is
    compiler-generated by default?
    Rolf Magnus, Jan 5, 2007
    #7
  8. fungus

    fungus Guest

    Rolf Magnus wrote:
    > That should work. Your code is a bit short, so it's hard to tell why it
    > wouldn't.


    I'll have another play with it and see what happens

    > It's better to show a minimal, but complete program that exhibits
    > the observed behavior.


    - but the code is so simple...(!)


    > Yep, that is a common problem with large, primitive obsessed objects.
    > You need to rethink your design here and group your data better.
    >
    > If you want a language that will make your design mistakes easier to
    > work with you've come to the wrong place.


    I have a class which represents a "material".
    Materials have a lot of properties, there's no
    way around that. I want to put materials in a
    std::map for lookup so I need an operator<. I
    need to compare two materials so I need an
    operator=.

    I don't see how there's a "design flaw" here.


    --
    <\___/>
    / O O \
    \_____/ FTB. For email, remove my socks.


    We’re judging how a candidate will handle a nuclear
    crisis by how well his staff creates campaign ads.
    It’s a completely nonsensical process.
    fungus, Jan 6, 2007
    #8
  9. fungus

    fungus Guest

    mlimber wrote:
    > fungus wrote:
    >>
    >> Why can't the compiler write operator==
    >> and operator< for me automatically?

    >
    > what is the compiler supposed to do with pointer members?
    > Should it compare values or pointed-to-addresses? If values, what
    > should it do if one or both pointers is null? What if a pointer is
    > simply uninitialized?


    You have exactly the same problem with assignment
    operator and copy constructor but the compiler
    seems happy enough to do those for me.

    --
    <\___/>
    / O O \
    \_____/ FTB. For email, remove my socks.


    We’re judging how a candidate will handle a nuclear
    crisis by how well his staff creates campaign ads.
    It’s a completely nonsensical process.
    fungus, Jan 6, 2007
    #9
  10. fungus

    fungus Guest

    Rolf Magnus wrote:
    > fungus wrote:
    >> Why can't the compiler write operator==
    >> and operator< for me automatically?
    >>

    > how would the compiler generate operator<?


    The code I'm writing at the moment looks like this:


    struct item {
    float value1;
    float value2;
    ...
    };

    bool operator<(const item& a, const item& b)
    {
    // value1
    if (a.value1 < b.value1) return true;
    if (b.value1 < a.value1) return false;

    // value2
    if (a.value2 < b.value2) return true;
    if (b.value2 < a.value2) return false;

    // ...

    // If we reach here then a and b are equal
    return false;
    }


    --
    <\___/>
    / O O \
    \_____/ FTB. For email, remove my socks.


    We’re judging how a candidate will handle a nuclear
    crisis by how well his staff creates campaign ads.
    It’s a completely nonsensical process.
    fungus, Jan 6, 2007
    #10
  11. fungus

    fungus Guest

    Jacek Dziedzic wrote:
    > fungus wrote:
    >> Why can't the compiler write operator==
    >> and operator< for me automatically?

    >
    > // how does the compiler know whether to
    > // compare by employee_name or by date_hired?
    >


    If I want specifics like these then I'll write
    appropriate code but I can think of many
    situations where all I want is generic compares
    and fast lookups (eg. std::map, std::lower_bound).


    --
    <\___/>
    / O O \
    \_____/ FTB. For email, remove my socks.


    We’re judging how a candidate will handle a nuclear
    crisis by how well his staff creates campaign ads.
    It’s a completely nonsensical process.
    fungus, Jan 6, 2007
    #11
  12. fungus

    fungus Guest

    fungus wrote:
    > Rolf Magnus wrote:
    >> That should work. Your code is a bit short, so it's
    >> hard to tell why it wouldn't.

    >
    > I'll have another play with it and see what happens...
    >


    I figured it out - it's all to do with namespaces.

    Here's a "broken" piece of code:

    #include <iostream>
    #include <string>

    namespace foo {
    class A {
    public:
    void writeTo(std::eek:stream& os) const {
    os << "A";
    }
    };
    void operator<<(std::eek:stream& os, const class B&);
    void test();
    }

    template<typename T, typename S>
    S& operator<<(S& d, const T& t)
    {
    t.writeTo(d);
    return d;
    }

    void foo::test()
    {
    A a;
    std::cout << a << '\n';
    }

    int main(int argc,char **argv)
    {
    foo::test();
    }


    The operator<< in namespace foo is hiding the template
    operator<< (which is in the global namespace).


    --
    <\___/>
    / O O \
    \_____/ FTB. For email, remove my socks.


    We’re judging how a candidate will handle a nuclear
    crisis by how well his staff creates campaign ads.
    It’s a completely nonsensical process.
    fungus, Jan 6, 2007
    #12
    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. Piotre Ugrumov
    Replies:
    3
    Views:
    368
    Nick Hounsome
    Jan 25, 2004
  2. Atlas
    Replies:
    13
    Views:
    497
    Atlas
    Oct 20, 2005
  3. Fei Liu
    Replies:
    5
    Views:
    344
    Maxim Yegorushkin
    Feb 25, 2006
  4. Mahain
    Replies:
    3
    Views:
    1,010
    James Kanze
    Dec 20, 2007
  5. Ying-Chieh Liao

    function overload (not operator overload)

    Ying-Chieh Liao, Oct 11, 2004, in forum: Perl Misc
    Replies:
    3
    Views:
    248
    Sherm Pendley
    Oct 11, 2004
Loading...

Share This Page