UE4 Mac构建编译报错 no template named “is_void_v” in namespace “std”

背景

UE4 Mac构建编译报错 no template named "is_void_v" in namespace "std" ,但WINDOWS没有遇到错误。

分析过程

1、is_void_v 是否属于C++17

从语法上看,AI说不只是 C++17 才有。早在C++14 就有 is_void_v 的用法了。

2、WINDOWS中is_void_v的定义

这段代码在WINDOWS下定义在

C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\type_traits

3、Mac中is_void_v的定义

在WINDOWS中,is_void_v 的定义是在: C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\type_traits ,那么在Mac机器中,它可能定义在哪个路径下?

我找到了它在Mac机器上的定义,位于:/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_void.h ,具体定义是:

复制代码
//代码1:
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___TYPE_TRAITS_IS_VOID_H
#define _LIBCPP___TYPE_TRAITS_IS_VOID_H

#include <__config>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_same.h>
#include <__type_traits/remove_cv.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#  pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

#if __has_builtin(__is_void)

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS is_void : _BoolConstant<__is_void(_Tp)> {};

#  if _LIBCPP_STD_VER >= 17
template <class _Tp>
inline constexpr bool is_void_v = __is_void(_Tp);
#  endif

#else

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS is_void : public is_same<__remove_cv_t<_Tp>, void> {};

#  if _LIBCPP_STD_VER >= 17
template <class _Tp>
inline constexpr bool is_void_v = is_void<_Tp>::value;
#  endif

#endif // __has_builtin(__is_void)

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___TYPE_TRAITS_IS_VOID_H
4、_LIBCPP_STD_VER的含义

_LIBCPP_STD_VER是 ​libc++(LLVM 的 C++ 标准库实现)内部用来表示其当前所支持的 C++ 标准版本的一个宏。它的值是一个整数,对应了不同的 C++ 标准发布年份。

这个宏的主要作用是让 libc++ 的代码能够根据不同的 C++ 标准版本条件地编译某些特性或提供特定版本的 API。以下是 _LIBCPP_STD_VER常见值及其对应的 C++ 标准的梳理:

if _LIBCPP_STD_VER >= 17

template <class _Tp>

inline constexpr bool is_void_v = __is_void(_Tp); // 或者 = is_void<_Tp>::value;

endif

上述代码意味着 ​is_void_v这个变量模板只有在 C++17 或更高版本下才会被定义和提供。这很好地解释了你最初的问题:is_void_v确实是 C++17 引入的特性。

5、理解 _LIBCPP_STD_VER与 __cplusplus的区别

你可能会想到另一个预定义宏 __cplusplus,它由编译器直接定义,用于指示编译器所遵循的 C++ 标准版本。

  • __cplusplus:由 编译器 定义,表示编译器当前正在编译所遵循的 C++ 标准模式。它的值也是年份,例如 C++17 模式下其值通常为 201703L。
  • _LIBCPP_STD_VER:由 libc++ 标准库头文件 定义,表示 libc++ 库本身实现所支持的最高或当前选择的 C++ 标准版本。

简单来说:

  • __cplusplus告诉你编译器在用什么模式。
  • _LIBCPP_STD_VER告诉你标准库在用什么模式。

在大多数正常配置下,_LIBCPP_STD_VER的值会和 __cplusplus的值保持一致(经过某种映射,例如 __cplusplus == 201703L时 _LIBCPP_STD_VER被定义为 17),因为它们需要协同工作。这个映射逻辑通常隐藏在 libc++ 的内部配置头文件(如 <__config>)中。

6、Mac中决定_LIBCPP_STD_VER 的地方
复制代码
//代码2:
public CppStandardVersion CppStandard = CppStandardVersion.Default;
static string GetCppStandardCompileArgument(CppCompileEnvironment CompileEnvironment)
{
    var Mapping = new Dictionary<CppStandardVersion, string>
    {
       { CppStandardVersion.Cpp14, " -std=c++14" },
       { CppStandardVersion.Cpp17, " -std=c++17" },
       { CppStandardVersion.Latest, " -std=c++17" },
       { CppStandardVersion.Default, " -std=c++14" }
    };
    return Mapping[CompileEnvironment.CppStandard];
}

在我的构建机中,该默认配置,读取的就是c++14,也就是Mac机用的也就是c++14.

7、WINDOWS是否是 c++14 ?

是的,在我的构建机中,WINDOWS 也是c++14。论述如下。在UE4中,我看到下面变量决定了c++的标准:

复制代码
public class ModuleRules 
{
    ...... 
    public CppStandardVersion CppStandard = CppStandardVersion.Default;
    ......
}

然而在WINDOWS的构建机中,我观察到UBT产生的编译命令中,没有 -std=c++14 或 -std=c++17 或 /std:c++latest 或 /Qstd=c++14 或 /std:c++17 或 /std:c++14 中的任何一个。我调试的代码位于 UnrealBuildTool.VCToolChain.AppendCLArguments_CPP() ,UnrealBuildTool.VCToolChain里的 ​​"VC"​​ 字面上指的是 ​Visual C++​,这是微软(Microsoft)提供的 C++ 编译工具链 。最终观察到下面这些参数,它们记录在EngineSource\Engine\Intermediate\Build\Win64\UE4Editor\Development\Launch\Module.Launch.cpp.obj.response :

/Zc:inline

/nologo

/Oi

/c

/Gw

/Gy

/Zm1000

/wd4819

/D_CRT_STDIO_LEGACY_WIDE_SPECIFIERS=1

/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS=1

/D_DISABLE_EXTENDED_ALIGNED_STORAGE

/source-charset:utf-8

/execution-charset:utf-8

/Ox

/Ot

/GF

/Ob2

/errorReport:prompt

/EHsc

/Z7

/MD

/bigobj

/fp:fast

/Zo

/Zp8

/we4456

/we4458

/we4459

/wd4463

/wd4838

/we4668

也就是说,没有显式声明 C++版本。那么,WINDOWS下UE4最终会以什么C++标准来编译呢?

在 Windows 下观察到的 UE4 编译命令中没有显式指定 C++ 标准(如 /std:c++17),这通常意味着它依赖于编译器的默认标准。结合你提到的 ModuleRules中的 CppStandard = CppStandardVersion.Default设置,分析如下:

8、总结

在Mac构建机和WINDOWS构建机中,构建机编译器都正在用着C++14,而非C++17 。

前面我们知道,mac中 要用 C++17,才能编译到 is_void_v,但 为什么WINDOWS用 c++14 却也能编译 is_void_v ?

因为,在 WINDOWS的定义( C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\type_traits )中,没有C++版本限制;

复制代码
_EXPORT_STD template <class _Ty>
_INLINE_VAR constexpr bool is_void_v = is_same_v<remove_cv_t<_Ty>, void>;

_EXPORT_STD template <class _Ty>
struct is_void : bool_constant<is_void_v<_Ty>> {};

而在 Mac的定义( /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_void.h )中,有C++版本限制;

复制代码
#  if _LIBCPP_STD_VER >= 17
template <class _Tp>
inline constexpr bool is_void_v = __is_void(_Tp);
#  endif

修复方法

因此,我们将所有的 std::(\^\<+)_v< 都替换为 std::($1)::value ,例如:

相关推荐
寒水馨20 小时前
macOS下载、安装openclaw-v2026.7.1(附安装包OpenClaw-2026.7.1.dmg)
macos·大模型·github·开源软件·ai助手·openclaw·gpt-5.6
白玉cfc1 天前
【iOS】MRC和ARC
macos·ios·cocoa
飞雪金灵1 天前
mac电脑 Maven下载安装和配置环境变量
macos·maven·maven下载安装·mac电脑环境
雨声不在1 天前
macos 12使用docker
macos·docker·容器
一叶龙洲1 天前
ubuntu26.04 xfce美化成mac
服务器·ubuntu·macos
李小白杂货铺1 天前
Oh My Zsh 简记
macos·macbook·zsh·主题·插件·oh my zsh·omz
fukai77222 天前
macOS防止休眠的菜单栏小工具
macos
web守墓人2 天前
【go语言】gotar:使用go语言复刻tar命令,并加入7z支持,可独立运行在windows、linux、macos上
linux·macos·golang
之歆3 天前
从 Mac 回到 Windows:用 PowerToys + AutoHotkey 找回熟悉手感
windows·macos
星辰即远方3 天前
字符串合法性检验
macos·ios·cocoa