Как обработать сложную рекурсию заголовка с вариантами и используя - PullRequest
1 голос
/ 08 июня 2019

У меня (абстрактно) 3 заголовка, два из которых содержат отдельные варианты, вызывающие другой из другого. Основная структура такова:

AB.hpp

#ifndef AB
#define AB

//#include "CD.hpp"

namespace HELLO {
    struct A;
    struct B;

    struct A{/*...*/};
    struct B{
        std::stack<CD_var> s;

        friend std::ostream &operator<<(std::ostream &os, B const &b){
            os << s.top();
            /*more code..*/
            return os;
        }
    };

    using AB_var = std::variant<A, B>;

    std::ostream &operator<<(std::ostream &os, AB_var const &v) {
        switch(v.index()){
            case 0: // A
                os << std::get<A>(v);
                break;
            case 1: // B
                os << std::get<B>(v);
                break;
            default:
                throw std::bad_variant_access();
        }
        return os;
    }
}

#endif

CD.hpp

#ifndef CD
#define CD

//#include "AB.hpp"

namespace HELLO {
    struct C;
    struct D;

    using CD_var = std::variant<C, D>;
    std::ostream &operator<<(std::ostream &os, CD_var const &v);

    struct C{
        std::stack<AB_var> s;
        std::stack<CD_var> t;

        friend std::ostream &operator<<(std::ostream &os, C const &c){
            os << s.top();
            os << t.top();
            /*more code..*/
            return os;
        }
    }

    struct D{/*...*/}

    std::ostream &operator<<(std::ostream &os, CD_var const &v) {
        switch(v.index()){
            case 0: // C
                os << std::get<C>(v);
                break;
            case 1: // D
                os << std::get<D>(v);
                break;
            default:
                throw std::bad_variant_access();
        }
        return os;
    }
}

#endif

ABCD.hpp использует оба элемента в AB.hpp и CD.hpp.

Теперь проблема в том, что, подумав об этом часами, я не смог найти способ правильно связать эти заголовки. Независимо от того, как я их связываю, из-за этого возвращается множество ошибок. Я хотел бы разделить AB и CD, поскольку они имеют разные функции. Пожалуйста, дайте мне способ заставить этот код работать. Спасибо.

Ответы [ 2 ]

2 голосов
/ 08 июня 2019

Одним из возможных решений является разделение заголовков на предварительные объявления и реализации:

// AB_forward.hpp

#pragma once
#include <ostream>
#include <variant>

struct A;
struct B;

using AB_var = std::variant<A, B>;
std::ostream & operator<<(std::ostream &, AB_var const &);

// CD_forward.hpp

#pragma once
#include <ostream>
#include <variant>

struct C;
struct D;

using CD_var = std::variant<C, D>;
std::ostream & operator<<(std::ostream &, CD_var const &);

// AB.hpp

#pragma once
#include "AB_forward.hpp"
#include "CD_forward.hpp"
#include <stack>

struct A { /*...*/ };
struct B { 
    std::stack<CD_var> s; 
    friend std::ostream & operator<<(std::ostream &, B const &);
};

// CD.hpp

#pragma once
#include "AB_forward.hpp"
#include "CD_forward.hpp"
#include <stack>

struct C { 
    std::stack<AB_var> s; std::stack<CD_var> t; 
    friend std::ostream & operator<<(std::ostream &, C const &);
};
struct D { /*...*/ };

// AB_CD.hpp   <- implementations are here

#include "AB.hpp"
#include "CD.hpp"

std::ostream & operator<<(std::ostream &, B const &) { /* ... */ }
std::ostream & operator<<(std::ostream &, AB_var const &) { /* ... */ }

std::ostream & operator<<(std::ostream &, C const &) { /* ... */ }
std::ostream & operator<<(std::ostream &, CD_var const &) { /* ... */ }

// main.cpp

#include "AB_CD.hpp"

/* ... */
1 голос
/ 08 июня 2019

Все, что вам нужно сделать, это разделить ваши заголовки на файлы .hpp & .cpp, объявления принадлежат файлам .hpp, а реализации принадлежат файлам .cpp, и в этот момент в AB.hpp включают CD.h, ив CD. cpp включает AB.hpp.Это должно сделать работу.

РЕДАКТИРОВАТЬ: вы также должны использовать предварительное объявление в файле CD.hpp для использования AB_variant.

Примерно так:

AB.hpp

#ifndef PROJECT_AB_H
#define PROJECT_AB_H

#include "CD.h"

namespace HELLO {
    struct A;
    struct B;

    struct A {/*...*/};

    struct B {
        std::stack<CD_var> s;

        friend std::ostream &operator<<(std::ostream &os, B const &b);
    };

    using AB_var = std::variant<A, B>;

    std::ostream &operator<<(std::ostream &os, AB_var const &v);
}
#endif

AB.cpp

#include "AB.h"

namespace HELLO {

    std::ostream &operator<<(std::ostream &os, AB_var const &v) {/*...*/}

    std::ostream &operator<<(std::ostream &os, B const &b) {
        //The right using is: b.s.top();
        /*more code..*/
        return os;
    }
}

CD.hpp

#ifndef PROJECT_CD_H
#define PROJECT_CD_H

namespace HELLO {
    struct A;
    struct B;
    using AB_var = std::variant<A, B>;

    struct C;
    struct D;

    using CD_var = std::variant<C, D>;

    std::ostream &operator<<(std::ostream &os, CD_var const &v);

    struct C {
        std::stack<AB_var> s;
        std::stack<CD_var> t;

        friend std::ostream& operator<<(std::ostream &os, C const &c);
    };

    struct D {/*...*/};
    /*...*/
}

#endif

CD.cpp

#include "CD.h"
#include "AB.h"

namespace HELLO {

    std::ostream &operator<<(std::ostream &os, CD_var const &v) {/*...*/}

    std::ostream& operator<<(std::ostream &os, C const &c) {
        //The right using is: c.s.top();
        //The right using is: c.t.top();
        /*more code..*/
        return os;
    }
}

Подробнее о сборникевремя: Заголовки, включающие друг друга в C ++

...