Выборочные неявные преобразования

У меня есть 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>), и поскольку он был единственным, о котором знал компилятор, он пытался использовать его для всего.

Короче говоря, при работе с кроссплатформенными вещами нужно педантично относиться к включению именно того, что необходимо (и не полагаться на то, что другие заголовки включают вещи, которые не связаны с ними).

Другие вопросы по тегам