STD ::访问std ::变体无法正常工作

std::visit on std::variant does not work as I expect

本文关键字:常工作 工作 std 访问 STD      更新时间:2023-10-16

给定以下(缩减为Essentials):

#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,但有相同的问题,除了更多的错误输出。谁能向我解释我做错了什么?

第一个版本是自我恢复的。由于该功能在自己的身体上是已知的,因此无问题。

第二版具有多个相互重新恢复的函数。您需要在定义之前使用的一个前向声明。

添加行

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

struct ExpressionOutputVisitor { ... };

之前

失败与解释有关,与std::visitstd::variant无关。