STD :: посещение STD :: вариант не работает, как я ожидаю - PullRequest
0 голосов
/ 17 марта 2019

Учитывая следующее (сведено к основам):

#include <memory>
#include <ostream>
#include <string>
#include <variant>

struct Cell;

using Expression =
    std::variant<std::string, std::shared_ptr<Cell>, std::nullptr_t>;

struct Cell {
    explicit Cell(Expression car, Expression cdr) : car_{car}, cdr_{cdr} {
    }

    Expression car_;
    Expression cdr_;
};

Я хотел создать выходной итератор для выражений. Моя первая попытка выглядела так:

 std::ostream& operator<<(std::ostream& out, const Expression& exp) {
     switch (exp.index()) {
         case 0:
             out << std::get<0>(exp);
             break;
         case 1: {
                 auto cell = std::get<1>(exp);
                 out << "( " << cell->car_ << " . " << cell->cdr_ << " )";
             }
             break;
         case 2:
             out << "()";
             break;
     }

     return out;
 }

Это сработало, но я думал, что смогу работать лучше (более читабельно, более легко обслуживаемо и т. Д.), Поэтому я придумал это.

struct ExpressionOutputVisitor {
    std::ostream& out_;

    ExpressionOutputVisitor(std::ostream& out) : out_{out} {
    }

    void operator()(std::string& arg) const {
        out_ << arg << '\n';
    }

    void operator()(std::shared_ptr<Cell>& arg) const {
        out_ << "( " << arg->car_ << " . " << arg->cdr_ << " )"; // error at arg->car_
    }

    void operator()(std::nullptr_t) const {
        out << "()";
    }
};

std::ostream& operator<<(std::ostream& out, Expression& exp) {
    std::visit(ExpressionOutputVisitor{out}, exp);
    return out;
}

... однако эта вторая версия не работает, и я озадачен, почему бы и нет. Ошибка компилятора (clang ++ 6.0.0 в Linux):

error: invalid operands to binary expression
      ('basic_ostream<char, std::char_traits<char> >' and 'Expression' (aka
      'variant<basic_string<char>, shared_ptr<Cell>, nullptr_t>'))
        out_ << "(" << arg->car_ << " " << arg->cdr_ << ")";
        ~~~~~~~~~~~ ^  ~~~~~~~~~

сопровождается обычной парой страниц изверга. Я также пытался с g ++ 7.3.0 с той же проблемой, за исключением еще большего количества ошибок. Может кто-нибудь объяснить мне, что я делаю не так?

1 Ответ

0 голосов
/ 17 марта 2019

Первая версия является саморекурсивной.Поскольку функция известна в своем собственном теле, она работает без проблем.

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

Добавить строку

std::ostream& operator<<(std::ostream& out, Expression& exp);

перед struct ExpressionOutputVisitor { ... };

Ошибка относится к точке объявления и не имеет ничего общего с std::visit или std::variant.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...