C++ 模块片段和命名空间出错?

Error with C++ module fragments and namespaces?

我想构建一个包含多个实现文件的模块。一个带有结构的文件被两个实现文件使用。

当我编译时,在 gcc 主干 (12) 和 11 中出现以下错误:

$HOME/bin/bin/g++ -std=c++20 -fmodules-ts -g -o test_optimization test_optimization.cpp optimization.cpp opt_structs.cpp golden.cpp brent.cpp
test_optimization.cpp: In function ‘int main()’:
test_optimization.cpp:13:3: error: ‘emsr’ has not been declared
   13 |   emsr::MinBracket<double> mb;
      |   ^~~~
test_optimization.cpp:13:20: error: expected primary-expression before ‘double’
   13 |   emsr::MinBracket<double> mb;
      |                    ^~~~~~

从我根本不理解模块到不完整的 g++ 实现等等,可能会发生一些非排他性的事情...

主要测试人员(test_optimization.cpp):

#include <cmath>

import emsr.opt;

int
main()
{
  emsr::MinBracket<double> mb;
}

模块接口(optimization.cpp):

export module emsr.opt;
export import :golden;
export import :brent;

一个实现模块(golden.cpp):

module;

#include <cmath>
#include <numbers>

export module emsr.opt:golden;

export import :structs;

namespace emsr
{
  template<typename Func, typename Real>
    void
    mean_bracket(Func func, MinBracket<Real>& mb)
    { }

  template<typename Func, typename Real>
    FuncPt<Real>
    golden(Func func, MinBracket<Real>& mb, Real tol)
    { return FuncPt<Real>(); }
} // namespace emsr

另一个实现模块(brent.cpp):

module;

#include <cmath>
#include <numbers>

export module emsr.opt:brent;

export import :structs;

namespace emsr
{
  template<typename Func, typename Real>
    FuncPt<Real>
    brent(Func func, Real ax, Real bx, Real cx, Real tol)
    { return FuncPt<Real>(); }

  template<typename Func, typename Deriv, typename Real>
    FuncPt<Real>
    brent_deriv(Func func, Deriv deriv, Real ax, Real bx, Real cx, Real tol)
    { return FuncPt<Real>(); }
} // namespace emsr

结构模块片段(opt_structs.cpp):

export module emsr.opt:structs;

namespace emsr
{
  template<typename Real>
    struct FuncPt
    {
      Real arg;
      Real val;

      FuncPt() = default;
    };

  template<typename Real>
    struct MinBracket
    {
      FuncPt<Real> a;
      FuncPt<Real> b;
      FuncPt<Real> c;
    };

  template<typename Real>
    struct DerivPt
    {
      Real arg;
      Real val;
      Real der;

      DerivPt() = default;
    };
}

我也在尝试用 gcc 找出模块,我不能发表评论所以我会 post 在这里。

gcc documentation 说:

Standard Library Header Units:

The Standard Library is not provided as importable header units. If you want to import such units, you must explicitly build them first. If you do not do this with care, you may have multiple declarations, which the module machinery must merge—compiler resource usage can be affected by how you partition header files into header units.

No new source file suffixes are required or supported. If you wish to use a non-standard suffix (see Overall Options), you also need to provide a -x c++ option too.2

根据 this blog post,对于 gcc,您需要根据我的理解分别编译头文件。他们使用标准库中的 iostream 作为示例。

While Clang comes with a mapping of standard headers to modules. Using GCC, we need to compile iostream manually.

> g++ -std=c++20 -fmodules-ts -xc++-system-header iostream
> g++ -std=c++20 -fmodules-ts hello_modular_world.cc

看起来他们使用 import <header>; 语法而不是 include。

> cat hello_modular_world.cc
import <iostream>;
int main() {
    std::cout << "Hello Modular World!\n";
}

我不确定这是否可以接受,但它有效,这就是我所做的:

我编译了系统头文件:

> g++-12 -std=c++20 -fmodules-ts -xc++-system-header cmath
> g++-12 -std=c++20 -fmodules-ts -xc++-system-header numbers

我把代码改成这样:

opt_structs.cpp

export module emsr.opt:structs;

export namespace emsr {
template <typename Real> struct FuncPt {
  Real arg;
  Real val;

  FuncPt() = default;
};

template <typename Real> struct MinBracket {
  FuncPt<Real> a;
  FuncPt<Real> b;
  FuncPt<Real> c;
};

template <typename Real> struct DerivPt {
  Real arg;
  Real val;
  Real der;

  DerivPt() = default;
};
} // namespace emsr

golden.cpp

module;

import <cmath>;
import <numbers>;

export module emsr.opt:golden;

export import :structs;

export namespace emsr {
template <typename Func, typename Real>
void mean_bracket(Func func, MinBracket<Real> &mb) {}

template <typename Func, typename Real>
FuncPt<Real> golden(Func func, MinBracket<Real> &mb, Real tol) {
  return FuncPt<Real>();
}
} // namespace emsr

brent.cpp

module;

import <cmath>;
import <numbers>;

export module emsr.opt:brent;

export import :structs;

export namespace emsr {
template <typename Func, typename Real>
FuncPt<Real> brent(Func func, Real ax, Real bx, Real cx, Real tol) {
  return FuncPt<Real>();
}

template <typename Func, typename Deriv, typename Real>
FuncPt<Real> brent_deriv(Func func, Deriv deriv, Real ax, Real bx, Real cx,
                         Real tol) {
  return FuncPt<Real>();
}
} // namespace emsr

optimization.cpp(同)

export module emsr.opt;
export import :golden;
export import :brent;

test_optimization.cpp

import <cmath>;
import emsr.opt;

int main() {
  emsr::MinBracket<double> mb;
  return 0;
}

我所做的只是将 #includes 更改为 import <header>; 并导出命名空间 emsr.

然后我这样编译:

> g++-12 -std=c++20 -fmodules-ts -g -c opt_structs.cpp
> g++-12 -std=c++20 -fmodules-ts -g -c brent.cpp
> g++-12 -std=c++20 -fmodules-ts -g -c golden.cpp
> g++-12 -std=c++20 -fmodules-ts -g -c optimization.cpp
> g++-12 -std=c++20 -fmodules-ts -g -c test_optimization.cpp
> g++-12 -std=c++20 test_optimization.o opt_structs.o brent.o golden.o optimization.o -o test_optimization

> ./test_optimization

请注意,我必须先编译 opt_structs.cpp,然后是 golden.cppbrent.cpp,然后是 optimization.cpp,然后是 main 文件。

同样,我不知道这是最好的还是正确的方法,我还在学习,但这是我试图解决这个问题的方法。