如何使用变体和使用复杂的标头递归

时间:2019-06-08 06:26:06

标签: c++ recursion header c++17

我(抽象地)有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中的两个元素。

现在的问题是,经过数小时的思考,我找不到正确链接这些标头的方法。无论我如何链接它们,由于此原因它都会返回带有大量错误消息的错误。我想将ABCD分开,因为它们具有不同的功能。请给我一种使此代码起作用的方法。谢谢。

2 个答案:

答案 0 :(得分:2)

一种可能的解决方案是将标头拆分为正向声明和实现:

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

您要做的就是将标头拆分为.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;
    }
}

有关编译时间的更多信息:Headers Including Each Other in C++