std :: variant上的std :: visit无法正常工作

时间:2019-03-17 05:38:12

标签: c++ c++17

给出以下内容(精简为基本内容):

#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;
}

...但是第二个版本不起作用,我为为什么不感到困惑。来自编译器的错误(在Linux上为clang ++ 6.0.0)是:

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 :(得分:0)

第一个版本是自递归的。由于该功能本身是已知的,因此可以正常工作。

第二个版本具有多个相互递归函数。在定义之前,您需要使用的前向声明。

添加行

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

struct ExpressionOutputVisitor { ... };之前

失败与声明点有关,与std::visitstd::variant没有关系。