Я обеспокоен конфликтом между двумя определениями operator<<
,
Предположим, что я большой поклонник библиотеки ACE и использую ACE_Time_Value в моем коде. Однажды я заметил, что ACE 6.x вышел, и попытался перенести мой код из ACE 5.x в 6.x. Тогда у меня возникла проблема: ACE 6.x недавно представлен operator<<(std::ostream &, const ACE_Time_Value &)
в глобальном пространстве имен, но мой код реализовал мою собственную версию operator<<
с эпохи 5.х и два operator<<
противоречили. К сожалению выход из «официального» operator<<
неудовлетворительно, и мне нужно продолжать использовать свою собственную версию. Как я могу притворяться, что нет «официального» operator<<
в глобальном пространстве имен? К счастью (?) Весь мой код находится в моем собственном пространстве имен.
Концептуально мою проблему можно сформулировать так:
#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();
}
Вы можете сделать что-то вроде ниже и использовать наследование:
#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<<'
}
}
Возможно, вы также должны сделать «NewACE_Time_Value» не копируемым, чтобы избежать проблем с нарезкой объектов.
Вот как бы я решил ваш концептуальный пример:
#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();
}
Поскольку ACE с открытым исходным кодом, не должно быть слишком сложно применять те же самые модификации, чтобы их <<operator
Перегрузка заключена в пространство имен.
Во-первых, вы должны добавить «return os;» у нашего оператора перегрузка (<<).
Во-вторых, добавьте директивы препроцессора к одному из двух << перегрузка вот так:
#ifdef Oper
ostream &operator<<(ostream &os, const ACE_Time_Value &)
{
os << "Banana" ; return os;
}
#endif
В итоге я определил объект-обертку с помощью 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;
}
}
Мы решили не использовать наследование, потому что мы не можем изменить существующие сигнатуры методов в структуре реактора ACE, такие как virtual int handle_timeout (const ACE_Time_Value ¤t_time, const void *act=0)