Проблемы с потоковым интерфейсом в C++

Итак, у меня есть виртуальный потоковый интерфейс на С++

class KxStream
{
public:
   virtual KxStream& operator<< ( u32 num ) = 0;
};

. Он имеет массу базовых операторов << для всех встроенных -типов. Я только что перечислил один.

Затем у меня есть несколько классов, которые реализуют потоковый интерфейс. Вот так:

class KxCbuf : public KxStream
{
public:
   KxStream& operator<<( u32 num );
}

Итак, есть реализация потокового интерфейса в KxCbuf. Все идет нормально. Затем у меня есть несколько классов, которые перегружают интерфейс потока :

class KxSymbol
{
   operator u32() const;
   friend KxStream& operator<<( KxStream& os, KxSymbol sym );
};

. Обратите внимание, что этот класс имеет оператор приведения к встроенному типу -. Теперь, когда я пытаюсь передать один из этих классов в один из классов, реализующих потоковый интерфейс, я получаю сообщение об ошибке :

KxCbuf buf;
KxSymbol sym;

buf << sym; // error!

. Компилятор путается в том, какие функции использовать. Gcc компилируется нормально,но говорит, что есть несколько способов сделать это. MSVC не компилируется, говоря, что существует несколько перегрузок:

src/variable.cpp(524) : error C2666: 'KxCbuf::operator <<' : 15 overloads have similar conversions

Я знаю, что происходит, но не знаю, как решить это удовлетворительным образом. Таким образом, компилятор может либо преобразовать KxCbuf -> KxStream, а затем вызвать функцию друга, что является правильным решением. Или он может привести KxSymbol -> u32, а затем вызвать оператор u32 << в KxCbuf, унаследованном от KxStream.

Я могу решить ее двумя (плохими )способами.

Я могу начать с потоковой передачи чего-то однозначного:

buf << "" << sym;

Таким образом, возвращаемое значение оператора первого потока для "" возвращает KxStream, и все в порядке. Или я могу реализовать избыточный оператор потока для класса реализации. Например. Я могу добавить следующее в KxSymbol:

friend KxStream& operator<<( KxCbuf& os, KxSymbol sym );

Первый ответ всегда работает -, но он уродлив. Второй ответ тоже некрасивый, в том, что мне приходится создавать избыточные операторы потока, и не всегда работает в том смысле, что реализации KxStream не всегда видны в местах, где мне нужно определить новые операторы потока.

В идеале я хотел бы, чтобы реализации интерфейса KxStream работали точно так же, как объекты KxStream, и избегали неявных приведений, вызывающих неоднозначные преобразования.

Как мне это решить?

(пс. Мне нужно создать свои собственные операторы потоковой передачи для пользовательской схемы сериализации для моей библиотеки. Я не могу использовать boost или аналогичные сторонние библиотеки, у которых есть собственные классы сериализации )

. @Edit :Есть несколько хороших ответов, связанных с контролем использования компилятором неявного преобразования, такого как преобразование в KxSymbol -> u32, к сожалению, это неявное преобразование важно для кода. Например, KxSymbol — это класс, который хранит строки в таблице и возвращает их в виде чисел, чтобы я мог сравнивать строки как числа. Например. если два символа не равны, то и строки не совпадают. Я также храню символы как числа в некоторых структурах данных.

Есть ли способ решить это с другой стороны,каким-то образом заставить компилятор понять, что реализации KxStream следует приводить к объектам KxStream, а не другим неявным приведениям?

Например, что, если я каким-то образом заставлю компилятор сначала преобразовать KxCbuf в KxStream, прежде чем использовать оператор<< для встроенных типов -. Это заставит его всегда предпочитать операторы перегрузки<< операторам KxStream. -для перегрузок потребуется одно приведение, а для KxStream — два.

6
задан Rafael Baptista 13 August 2012 в 16:19
поделиться