переполнение стека с использованием примера std :: visit - PullRequest
0 голосов
/ 13 сентября 2018

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

#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. Итак, как парень в этой ссылке заставляет ее работать?

1 Ответ

0 голосов
/ 13 сентября 2018

Вот пример уменьшенного примера, который не требует 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";
}

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

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