3

I'm troubled by conflict between two definitions of operator<<.

Suppose that I've been a great fan of ACE library and been using ACE_Time_Value in my code. One day I noticed ACE 6.x was out and tried to migrate my code from ACE 5.x to 6.x. Then I got a problem: ACE 6.x newly introduced operator<<(std::ostream &, const ACE_Time_Value &) in the global namespace, but my code had implemented my own version of operator<< since 5.x era, and two operator<< conflicted. Unfortunately the output from the "official" operator<< is unsatisfactory and I need to keep using my own version. How can I pretend there's no "official" operator<< in the global namespace? Luckily(?) all my code is under my own namespace.

Conceptually my problem can be summarized as:

#include <iostream>
using namespace std;

struct ACE_Time_Value { };
ostream &operator<<(ostream &os, const ACE_Time_Value &) { os << "Apple" ; }
void foo(const ACE_Time_Value &) { cout << "Cherry" << endl; }

namespace mine {
    ostream &operator<<(ostream &os, const ACE_Time_Value &) { os << "Banana" ; }
    void foo(const ACE_Time_Value &) { cout << "Durian" << endl; }

    void bar() {
        ACE_Time_Value t;
        ::mine::foo(t); // OK
        // cout << "The current time is " <<
        //   t << endl; // error: ambiguous overload for 'operator<<'
    }
}

int main() {
    mine::bar();
}
2
  • That's a horrible problem and I can't find any good solution. Some ugly workarounds could be wrapping ostreams into a helper class My_ostream and provided with an operator<< that works just the same as the std::ostream version for all types but ACE_Time_Value, and then use those wrapped streams instead of standard ones. Commented Nov 26, 2015 at 9:48
  • commenting out the bad operator<< from the vendor headers might be the best solution Commented Nov 26, 2015 at 11:47

4 Answers 4

1

You can do something like below and make use of inheritance:

#include <iostream>
using namespace std;

struct ACE_Time_Value { };
ostream &operator<<(ostream &os, const ACE_Time_Value &) { os << "Apple" ; return os; }
void foo(const ACE_Time_Value &) { cout << "Cherry" << endl; }

namespace mine {
        struct New_ACE_Time_Value: ACE_Time_Value {};

        ostream &operator<<(ostream &os, const New_ACE_Time_Value &) { os << "Banana" ;
            return os;
        }
        void foo(const ACE_Time_Value &) { cout << "Durian" << endl; }

        void bar() {
                New_ACE_Time_Value t;
                ::mine::foo(t); // OK
                cout << "The current time is " <<
                   t << endl; // error: ambiguous overload for 'operator<<'
        }
}

Probably you should also make 'NewACE_Time_Value' non copyable to shrug off object slicing issues.

Sign up to request clarification or add additional context in comments.

Comments

0

This is how I would solve your conceptual example:

#include <iostream>
using namespace std;

struct ACE_Time_Value { };

namespace ACE
{
    ostream &operator<<(ostream &os, const ACE_Time_Value &) { os << "Apple" ; return os; }
}

void foo(const ACE_Time_Value &) { cout << "Cherry" << endl; }

namespace mine {
    ostream &operator<<(ostream &os, const ACE_Time_Value &) { os << "Banana" ; return os; }
    void foo(const ACE_Time_Value &) { cout << "Durian" << endl; }

    void bar() {
        ACE_Time_Value t;
        ::mine::foo(t); // OK
        cout << "The current time is " << t << endl;
    }
}

int main() {
    mine::bar();
}

Since ACE is open-source, it shouldn't be too hard to apply the same modifications so that their <<operator overload is wrapped inside a namespace.

Comments

0

First, you should add "return os;" in our operator overloading (<<). Second, add Preprocessor directives to one of two << overloading like this:

#ifdef Oper
ostream &operator<<(ostream &os, const ACE_Time_Value &) 
{
  os << "Banana"    ; return os; 
}
#endif

Comments

0

I ended up in defining a wrapper object with operator<<.

namespace mine {
    void foo(const ACE_Time_Value &) { cout << "Durian" << endl; }
    struct AceTimePrinter {
        const ACE_Time_Value &tv;
        AceTimePrinter(const ACE_Time_Value &tv) : tv(tv) { }
        inline friend std::ostream &operator<<(
                std::ostream &os, const AceTimePrinter &o) {
            const ACE_Time_Value &tv = o.tv;
            return os << "Durian" ;
        }
    };

    void bar() {
        ACE_Time_Value t;
        ::mine::foo(t); // OK
        cout << "The current time is " <<
            AceTimePrinter(t) << endl;
    }
}

We chose not to use inheritance because we cannot change existing method signatures in the ACE reactor framework, such as virtual int handle_timeout (const ACE_Time_Value &current_time, const void *act=0)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.