4

I was experimenting with c++ 20 modules

I am trying to do the 'virtual constructor' idiom, i.e. do the following

class Base{
public:
  virtual ~Interface() = default;
  virtual void DoStuff() = 0;
  static std::unique_ptr<Base> Create();
}

class Impl : public Base{
public:
  void DoStuff() override;
}

std::unique_ptr<Base> Base::Create(){
  return std::make_unique<Impl>();
}

Without modules i can place declarations of Base in base.h, declaration of Impl in impl.h, this way the clients don't see the Impl class, and both impl.cpp and base.cpp can compile.

I know with modules it is possible to keep everything in a single module, and simply do not export the Impl class. But suppose we have many different implementations classes, and each one is big and comes with its own dependencies, in this case i would like to place Interface and Impl into different modules - for better structure and readability, and to isolate dependencies.

But with modules and module partition this doesn't seem possible, because partition :base needs to import :impl (for the virtual constructor to work), and partition impl needs to import :base to be able to derive from Base.

What am i doing wrong? Or maybe i am just thinking in old terms and the solution with 1 big module is perfectly fine? (Another possible solution would be to use an ordinary function instead of a static method).

3
  • Are you sure this is a good example? I mean, Create() can't be static and can't be implemented by Base. In fact it must be pure virtual in Base Commented Mar 23, 2021 at 23:44
  • Can we have a complete header-based example? Commented Mar 24, 2021 at 5:41
  • What a module import is not exported, unless you use export import moduleImpl;
    – Jarod42
    Commented Mar 24, 2021 at 9:59

1 Answer 1

2

To break the dependencies you need to separate Base and Impl. I got this working in msvc with the /internalPartition flag

//m.ixx
module;
#include "pch.h"
#include <memory>
export module m;

export
class Base {
public:
    virtual ~Base() = default;
    virtual void DoStuff() = 0;
    static std::unique_ptr<Base> Create();
};
//m.cpp
module;
#include "pch.h"
#include <memory>
#include <iostream>
module m;

class Impl : public Base {
public:
    void DoStuff() override
    {
        std::cout << "hello\n";
    }
};

std::unique_ptr<Base> Base::Create() {
    return std::make_unique<Impl>();
}
1
  • 1
    m.cpp is not a partition unit, so it should not use the /internalPartition flag. It should compile just fine without this flag. Commented Jul 1, 2023 at 2:30

Not the answer you're looking for? Browse other questions tagged or ask your own question.