Выборочные неявные преобразования
У меня есть Value
класс, который может содержать значение различных типов данных.
class Value
{
private:
union
{
int Integer;
double Real;
bool Boolean;
};
ValueTypes valType;
public:
Value();
Value(double Val);
Value(int Val);
Value(bool Val);
/* ... */
friend std::ostream& operator <<(std::ostream& stream, const Value& val);
}
Я хотел бы перегрузить <<
оператор, так что значение может быть напечатано без проблем с исследованием его типа.
Это моя текущая реализация:
std::ostream &operator <<(std::ostream &os, const Value &val)
{
switch (val.valType)
{
case ValueTypes::Real:
os << val.Real;
break;
case ValueTypes::Integer:
os << val.Integer;
break;
case ValueTypes::Boolean:
os << (val.Boolean ? "True" : "False");
break;
}
return os;
}
Во-первых, при компиляции с g++ (IDE CodeBlocks, Ubuntu) реализация вызывает неявное преобразование в Value
, Когда тип значения Integer
или же Real
, os <<
заявление бросает их Value
, который затем обращается к ostream
перегрузка снова и снова (бесконечная рекурсия), поэтому я получаю ошибку сегментации.
Во-вторых, при компиляции с Visual C++ неявное преобразование пропадает, и оно просто печатает значения (не вызывает неявный конструктор).
Заметки:
Я хочу сохранить неявные конструкторы, так как это повышает удобочитаемость и облегчает обслуживание в других разделах моего проекта.
Кроме того, я нашел следующее сообщение в блоге, но не смог настроить свой код, чтобы он выполнялся так, как я хочу (использование шаблонов было немного выше моего нынешнего понимания синтаксиса cpp).
Что я могу сделать, чтобы отключить неявные преобразования в конкретном ostream
функция перегрузки?
РЕДАКТИРОВАТЬ: с -Wall
включен я не получаю предупреждений в CodeBlocks.
1 ответ
Вам нужно #include <ostream>
, Причина, по которой это не работает, заключается в том, что это заголовок, который на самом деле определяет std::ostream
и все эти полезные operator<<
функции.
Причина, по которой он не волнуется и не жалуется на "нет определения std::ostream
" (или другой <<
операторы) происходит из-за предварительной декларации. Если вы перенаправляете объявление типа, вы можете использовать его как указатель или ссылку (если вы не пытаетесь получить к нему доступ). Вы можете сделать некоторые вещи с неполным типом.
Те другие заголовки, которые вы включали, скорее всего были объявлены вперед std::ostream
, но никогда не давал полного определения этому и всем <<
операторы. По крайней мере, в вашей системе Ubuntu. В других системах возможно, что другие заголовки могли включать <ostream>
или, по крайней мере, некоторые из определений, которые <ostream>
делает. Ваш operator<<
был, вероятно, единственным, что компилятор видел (потому что вы не включили <ostream>
), и поскольку он был единственным, о котором знал компилятор, он пытался использовать его для всего.
Короче говоря, при работе с кроссплатформенными вещами нужно педантично относиться к включению именно того, что необходимо (и не полагаться на то, что другие заголовки включают вещи, которые не связаны с ними).