我最近一直在试验 MSVC 提供的模块实现,我遇到了一个有趣的场景。我有两个在它们的接口中相互依赖的类,这意味着我必须使用前向声明来编译它。以下代码显示了一个示例:
Module interface
export module FooBar;
export namespace FooBar {
class Bar;
class Foo {
public:
Bar createBar();
};
class Bar {
public:
Foo createFoo();
};
}
Run Code Online (Sandbox Code Playgroud)
Module implementation
module FooBar;
namespace FooBar {
Bar Foo::createBar() {
return Bar();
}
Foo Bar::createFoo() {
return Foo();
}
}
Run Code Online (Sandbox Code Playgroud)
现在我想将这两个类拆分为它们自己的名为Foo和的模块Bar。但是,每个模块都需要导入另一个模块,因为它们的接口相互依赖。根据目前的模块提案,不允许循环接口导入。这篇文章建议使用proclaimed ownership声明,但是在模块的MSVC实现中似乎还没有实现。
因此,我是否正确假设目前无法使用 MSVC 提供的当前实现解决这种情况?还是我缺少一些替代方案?在这种情况下,情况非常简单,但是我在模块化具有许多具有此类依赖关系的类的库时遇到了这个问题。我意识到循环依赖通常表明设计不佳,但在某些情况下,它们不可避免或难以重构。
当使用 clang 12 构建 c++20 模块时(它也使用 clang 10 重现)从模块导出全局变量并在另一个编译单元中从同一个导出类声明全局变量会导致“'vtable for foo'的多重定义” ”。
我的理解是,c++20 模块可以使用单个 cppm 源创建(clang 对模块使用 cppm),并且编译器将从它生成模块声明和定义。在这种情况下,clang++ 似乎确实生成了两次 vtable。
这是设置
foo.cppm:
export module foo;
export struct foo {
virtual void vf();
};
void foo::vf() {}
export foo module_foo; // variable, exported
Run Code Online (Sandbox Code Playgroud)
主.cpp:
import foo;
foo main_foo;
int main() {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
构建主可执行文件的编译步骤:
/usr/lib/llvm-12/bin/clang++ -std=c++20 -fmodules --precompile foo.cppm -o foo.pcm
/usr/lib/llvm-12/bin/clang++ -std=c++20 -fmodules --compile foo.cppm -o foo.o
/usr/lib/llvm-12/bin/clang++ -std=c++20 -fmodules -fmodule-file=foo.pcm --compile main.cpp -o main.o
/usr/lib/llvm-12/bin/clang++ -std=c++20 -fmodules foo.o …Run Code Online (Sandbox Code Playgroud) 查看GCC C++ 语言功能支持状态页面,我发现 C++20 模块支持的两个方面仍然缺失,其中之一是部分支持:
考虑到我们已经 2022 年了,为什么会出现这种情况?对于实施这些措施是否存在分歧?这仅仅是开发人员时间不足的问题吗?
Clang和MSVC已经支持来自未完成的C ++ 20标准的Modules TS。我可以使用CMake或其他构建系统来构建基于模块的项目吗?
我目前正在尝试在应该在 Windows (MSVC) 和 Linux (Clang 和/或 GCC) 上编译的代码中使用 c++ 模块。
我目前正在 Visual Studio 中进行开发,并使用“标准一致性模式”(/permissive-) 使我的代码尽可能可移植。
但是下面的代码:
import std.core;
int main()
{
std::cout << "Hello, World! haha" << std::endl;
std::vector<int> myVec{4};
std::map<std::string, size_t> myMap;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
无法使用 /permissive- 标志进行编译。我收到以下错误:
E3223 找不到要导入的模块文件“std.core”
错误 C2664:“int _CrtDbgReport(int,const char *,int,const char *,const char *,...)”:无法将参数 4 从“int”转换为“const char *”
我认为“std.core”可能仅适用于 Windows,因此我尝试了以下操作(我在许多示例中都看到了):
import <iostream>;
import <vector>;
import <map>;
Run Code Online (Sandbox Code Playgroud)
但它会导致以下错误:
错误 C7612:找不到“PATH_TO_VS\include\iostream”的标头单元
错误 C7612:找不到“PATH_TO_VS\include\vector”的标头单元
错误 C7612:找不到“PATH_TO_VS\include\map”的标头单元
注意:PATH_TO_VS\include 中实际上有名为“iostream”、“vector”和“map”的文件。
因此我想知道导入 c++ 模块的标准方法是什么?如果“import std.core”是标准方式,为什么不使用 /permissive- 进行编译?
我正在使用 Visual …
我正在尝试使用 C++20 中的模块。我自己的模块一切正常;我可以正常创建和使用它们。
但是,如果我想导入标准模块(std.core、std.regex 等),我会收到以下错误,并且在互联网上找不到类似的内容:
E3373 IFC 文件“C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.31.31103\ifc\x64/Debug/std.core.ifc”具有不受支持的版本 0.41
我已经看到.ixx、.cxx、.cpp并.cppm与 c++20 模块一起使用。
众所周知,C++23 支持标准库模块。直到 2023 年 5 月,MSVC 都支持它,但我们需要像Microsoft 博客提到的那样手动添加标准库模块。
import std但是在CMake项目中如何使用呢?MS博客没有提到这一点。并且这些文件无法工作。(该std.ifc文件来自微软博客教程:(cl /std:c++latest /EHsc /nologo /W4 /MTd /c "%VCToolsInstallDir%\modules\std.ixx"在msvc x64本机控制台中使用))
CMakeList.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.26)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${CMAKE_PROJECT_NAME})
set(CMAKE_CXX_STANDARD 23)
project(1-1)
add_executable(${CMAKE_PROJECT_NAME})
target_sources(${CMAKE_PROJECT_NAME}
PUBLIC
FILE_SET all_my_modules TYPE CXX_MODULES FILES
main.cpp
std.ifc
)
Run Code Online (Sandbox Code Playgroud)
主程序
CMAKE_MINIMUM_REQUIRED(VERSION 3.26)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${CMAKE_PROJECT_NAME})
set(CMAKE_CXX_STANDARD 23)
project(1-1)
add_executable(${CMAKE_PROJECT_NAME})
target_sources(${CMAKE_PROJECT_NAME}
PUBLIC
FILE_SET all_my_modules TYPE CXX_MODULES FILES
main.cpp
std.ifc
)
Run Code Online (Sandbox Code Playgroud)
MSVC 显示:
import …Run Code Online (Sandbox Code Playgroud) (有关我正在使用的特定版本的Boost和Clang的信息,请参阅问题的结尾)
使用新的实验性-fmodules功能在master/HEAD中编译Clang,使用下面显示的命令行选项编译以下文件时出现构建错误:
#include <iterator>
#include <boost/move/iterator.hpp>
Run Code Online (Sandbox Code Playgroud)
编译命令和错误:
anhall@leviathan: <path-to-clang-install-from-master>/bin/clang++ -o file.o -c file.cpp --std=c++1z -stdlib=libc++ -fmodules
In file included from file.cpp:2:
In file included from /usr/local/include/boost/move/iterator.hpp:27:
/usr/local/include/boost/move/detail/iterator_traits.hpp:60:17: error: reference to 'random_access_iterator_tag' is ambiguous
typedef std::random_access_iterator_tag iterator_category;
^
/Users/anhall/impersonal/code/llvm-reflexpr/install/bin/../include/c++/v1/iterator:438:30: note: candidate found by name lookup is 'std::__1::random_access_iterator_tag'
struct _LIBCPP_TYPE_VIS_ONLY random_access_iterator_tag : public bidirectional_iterator_tag {};
^
/usr/local/include/boost/move/detail/iterator_traits.hpp:34:8: note: candidate found by name lookup is 'std::random_access_iterator_tag'
struct random_access_iterator_tag;
^
/usr/local/include/boost/move/detail/iterator_traits.hpp:71:17: error: reference to 'random_access_iterator_tag' is ambiguous
typedef std::random_access_iterator_tag iterator_category;
^
/Users/anhall/impersonal/code/llvm-reflexpr/install/bin/../include/c++/v1/iterator:438:30: …Run Code Online (Sandbox Code Playgroud) 我正在创建一个库,并且 C++20 模块内有一个类模板,我想添加一个实例化,以减少使用我的库的每个项目的编译时间。
这些不同的实现是否等效,或者是否有更好的方法来实现?
1)
//mod.cpp
export module mod;
export template<typename T>
struct mystruct{ T i;};
export template class mystruct<int>;
Run Code Online (Sandbox Code Playgroud)
//mod.cpp
export module mod;
export template<typename T>
struct mystruct{ T i;};
template class mystruct<int>;
Run Code Online (Sandbox Code Playgroud)
//mod.cpp
export module mod;
export template<typename T>
struct mystruct{ T i;};
export extern template class mystruct<int>;
//mod_impl.cpp
module mod;
template class mystruct<int>;
Run Code Online (Sandbox Code Playgroud)
编辑:这个答案只说 2. 有效,但我的观点是 1. 和 3. 是否也等于 2.