简体   繁体   English

C++20 模块“循环依赖”

[英]C++20 Modules “cyclic dependency”

Im trying to include a module within another module, but i can't compile due to the following error:我试图在另一个模块中包含一个模块,但由于以下错误我无法编译:

"Cannot build the following source files because there is a cyclic dependency between them: Module1.ixx depends on Module2.ixx depends on Module1.ixx." “无法构建以下源文件,因为它们之间存在循环依赖关系:Module1.ixx 依赖于 Module2.ixx 依赖于 Module1.ixx。”

I want to modClass1_ contain modClass2_ class and modClass2_ contain a pointer to static modClass1_.我想 modClass1_ 包含 modClass2_ class 和 modClass2_ 包含指向 static modClass1_ 的指针。


Code i tried with success with C++17 Header and Source files (.h and.cpp)我尝试使用 C++17 Header 和源文件(.h 和.cpp)成功的代码

// Class1.h
#pragma once
#include "Class2.h"
class modClass2_;
class modClass1_
{
public:
    modClass1_() {};
    ~modClass1_() {};
    int V = 2;
    int getV() { return V; };
    static modClass2_ mc2;
};
extern modClass1_ mc1;
// Class1.cpp
#include "Class1.h"
modClass1_ mc1;
modClass2_ modClass1_::mc2;
// Class2.h
#pragma once
#include "Class1.h"
class modClass2_
{
public:
    modClass2_() {};
    ~modClass2_() {};
    int V = 1;
    int getV() { return V; };
    int getClass1V();
};
// Class2.cpp
#include "Class2.h"
int modClass2_::getClass1V()
{
    return mc1.V;
}
// Main.cpp
#include "Class1.h"
#include <iostream>
int main()
{
    std::cout << mc1.getV() << "\n"; // gets modClass1_ V directly
    std::cout << mc1.mc2.getClass1V() << "\n"; // gets modClass1_ V through modClass2_ through modClass1_
    std::cout << mc1.mc2.getV() << "\n"; // gets modClass2_ V through modClass1_
}

Code i tried but failed with C++20 Modules (.ixx)我尝试过但使用 C++20 模块 (.ixx) 失败的代码

// Module1.ixx
export module Module1;
import Module2;
export class modClass1_
{
public:
    modClass1_() {};
    ~modClass1_() {};
    int getV() { return V; };
    modClass2_ mc2;
    int getModule2V() { return mc2.V; };
    int V = 1;
};
export modClass1_ mc1;
// Module2.ixx
export module Module2;
import Module1;
export class modClass2_
{
public:
    modClass2_() {};
    ~modClass2_() {};
    int getV() { return V; };
    int getModule1V() { return mc1.V; };
    int V = 2;
};

Any help/suggestion will be appreciated.任何帮助/建议将不胜感激。

Environment: Visual Studio 2019 |环境:Visual Studio 2019 | MSVC-2019 | MSVC-2019 | C++20 | C++20 | Windows 10 Pro Windows 10 临

Just like with header files, you can separate out module interface files from module implementation files.就像头文件一样,您可以将模块接口文件与模块实现文件分开。 Example:例子:

Module1.ixx:模块1.ix:

export module Module1;

import Module2;

export class modClass1_
{
public:
  modClass1_() {};
  ~modClass1_() {};
  int getV() { return V; };
  modClass2_ mc2;
  int getModule2V() { return mc2.V; };
  int V = 1;
};
export modClass1_ mc1;

Module2.ixx:模块2.ix:

export module Module2;

export class modClass2_
{
public:
  modClass2_() {};
  ~modClass2_() {};
  int getV() { return V; };
  int getModule1V();
  int V = 2;
};

Module2.cpp:模块2.cpp:

import Module1;
import Module2;

int modClass2_::getModule1V()
{
  return mc1.V;
}

main.cpp:主.cpp:

#include <iostream>

import Module1;
import Module2;

int main()
{
  // NB: mc1 is a symbol imported from Module1
  std::cout << "mc1.V: " << mc1.V << '\n';
  std::cout << "mc1.getModule2V: " << mc1.getModule2V() << '\n';

  modClass2_ mc2;
  std::cout << "mc2.V: " << mc2.V << '\n';
  std::cout << "mc2.getModule1V: " << mc2.getModule1V() << '\n';
}

Note that modClass2_ 's interface doesn't require anything from Module1 and therefore Module2.ixx doesn't have import Module1;请注意, modClass2_的接口不需要来自Module1任何内容,因此Module2.ixx没有import Module1; . . Module2.cpp , where the implementation lives, does.实现所在的Module2.cpp确实如此。

In my example I've moved as little as possible from Module2.ixx into a Module2.cpp implementation file but in practice you might well want to move more things out of the interface.在我的示例中,我尽可能少地从Module2.ixxModule2.cpp实现文件中,但实际上您可能希望将更多内容移出接口。

I had a tree data structure split into two modules that needed to reference each other, and posted an answer how to make it work.我将一个树数据结构拆分为两个需要相互引用的模块,并发布了如何使其工作的答案 Copypasting it, here is a desperate solution to break a circular dependency by using a template:复制粘贴它,这是通过使用模板打破循环依赖的绝望解决方案:

// A_impl.cc

export module A_impl;

export template <typename B> class A_impl {
    public:
        void f(B& b) {}
};
// B.cc

export module B;

import A_impl;

export class B;

typedef A_impl<B> A;

export class B {
    public:
        void f(A& a) {}
};
// A.cc

export module A;

export import A_impl;
import B;

export typedef A_impl<B> A;
// main.cc

import A;
import B;

int main(void) {
    A a;
    B b;

    a.f(b);
    b.f(a);

    return 0;
}

At the moment clang doesn't support module partitions so with that toolchain this seems to be the only way to define A and B in different files (without #include ) while placing them in modules.目前,clang 不支持模块分区,因此使用该工具链,这似乎是将 A 和 B 放置在模块中时在不同文件中定义 A 和 B 的唯一方法(没有#include )。 With Visual Studio module partitions may or may not allow a cleaner structure.使用 Visual Studio 模块分区可能允许也可能不允许更清晰的结构。

Tested with gcc, module partitions can solve the problem using forward declarations and internal module linkage.经gcc测试,模块分区可以解决使用前向声明和内部模块链接的问题。 Note: This doesn't setup modules to depend on each other, the entire cyclic dependency is defined in a single module.注意:这不会将模块设置为相互依赖,整个循环依赖项都定义在单个模块中。

// A.cc

export module Cyclic:A;

export class B;
export class A {
public:
    char name() { return 'A'; }
    void f(B& b);
};
// B.cc

export module Cyclic:B;

export class A;
export class B {
public:
    char name() { return 'B'; }
    void f(A& a);
};
// A_impl.cc

module Cyclic:A_impl;

import Cyclic:A;
import Cyclic:B;

import <iostream>;

void A::f(B& b) {
  std::cout << name() << " calling " << b.name() << std::endl;
}
// B_impl.cc

module Cyclic:B_impl;

import Cyclic:B;
import Cyclic:A;

import <iostream>;

void B::f(A& a) {
  std::cout << name() << " calling " << a.name() << std::endl;
}
// Cyclic.cc

export module Cyclic;
export import :A;
export import :B;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM