Переполнение стека с использованием примера std :: visit

Я пытаюсь заставить этот код работать с добавленным вызовом печати, но эта программа вызывает переполнение стека:

#include <iostream>
#include <variant>

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/support.hpp>

auto const unquoted_text_field = *(boost::spirit::x3::char_ - ',' - boost::spirit::x3::eol);

struct text { };
struct integer { };
struct real { };
struct skip { };
typedef std::variant<text, integer, real, skip> column_variant;

std::ostream& operator<< (std::ostream& os, column_variant const& v) {
    std::visit([&os](auto const& e) { os << e; }, v);
    return os;
}

struct column_value_parser : boost::spirit::x3::parser<column_value_parser> {
    typedef boost::spirit::unused_type attribute_type;

    std::vector<column_variant>& columns;
    size_t mutable pos = 0;
    struct pos_tag;

    column_value_parser(std::vector<column_variant>& columns)
        : columns(columns)
    { }

    template<typename It, typename Ctx, typename Other, typename Attr>
    bool parse(It& f, It l, Ctx& /*ctx*/, Other const& /*other*/, Attr& /*attr*/) const {

        std::cout << columns[pos] << std::endl;
        return true;
    }
};

int main() {

    std::string input = "Hello,1,13.7,XXX\nWorld,2,1e3,YYY";
    std::vector<column_variant> columns = { text{}, integer{}, real{}, skip{} };

    auto at = input.begin();
    boost::spirit::x3::parse(at, input.end(),
        (column_value_parser(columns) % ',') % boost::spirit::x3::eol);
}

И в этом есть смысл, потому что он скрывается в рекурсивном вызове << operator. Итак, как парень из эта ссылка заставляет это работать?

0
0
238
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот сокращенный пример, который не требует Boost.Spirit (и поэтому компилируется намного быстрее):

#include <iostream>
#include <variant>

struct text { };
typedef std::variant<text> column_variant;

std::ostream& operator<< (std::ostream& os, column_variant const& v) {
    std::visit([&os](auto const& e) { os << e; }, v); 
    return os; 
}

int main() {
    column_variant v;
    std::cout << v;
}

Итак, первый вопрос, который у меня возник, когда я увидел ваш код, на самом деле: как он вообще компилируется? Я ожидал, что этого не произойдет, и был удивлен, когда это произошло. И причина, по которой он компилируется, на самом деле та же самая причина, по которой вы получаете переполнение стека, то есть ...

Что это на самом деле делает?

std::cout << text{};

Нет operator<< с text, верно? Но есть являетсяoperator<<, принимающий аргумент, который может быть построен из text: column_variant! Поскольку ни один из типов в вашем variant не поддерживает независимую потоковую передачу, попытка потоковой передачи любого из них приводит к рекурсивному вызову оператора варианта потока.

Вставьте что-то вроде этого:

std::ostream& operator<<(std::ostream& os, text) {
    return os << "text";
}

И больше никакой рекурсии.

Спасибо, Барри. Пощечина, леса не видно ... Я использую типы и ожидаю, что компилятор откопает std :: string, int и т. д. Конечно, не будет, мне нужно было закончить перегрузку.

lakeweb 13.09.2018 18:57

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