Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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."

I want to modClass1_ contain modClass2_ class and modClass2_ contain a pointer to static modClass1_.


Code i tried with success with C++17 Header and Source files (.h and .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)

// 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 | MSVC-2019 | C++20 | Windows 10 Pro

like image 602
Pedro Duarte Avatar asked Oct 27 '25 12:10

Pedro Duarte


1 Answers

Just like with header files, you can separate out module interface files from module implementation files. Example:

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;

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

Module2.cpp:

import Module1;
import Module2;

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

main.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;. Module2.cpp, where the implementation lives, does.

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.

like image 90
Nathan Pierson Avatar answered Oct 30 '25 01:10

Nathan Pierson