libc++ 的 std::is_literal_type 是如何工作的?

How does libc++'s std::is_literal_type work?

这与 std::is_literal_typestd::is_standard_layout 的情况相同。

libc++中std::is_literal_type的实现是

template <class _Tp> struct _LIBCPP_TEMPLATE_VIS is_literal_type
#ifdef _LIBCPP_IS_LITERAL
    : public integral_constant<bool, _LIBCPP_IS_LITERAL(_Tp)>
#else
    : integral_constant<bool, is_scalar<typename remove_all_extents<_Tp>::type>::value ||
                              is_reference<typename remove_all_extents<_Tp>::type>::value>
#endif
    {};

没有_LIBCPP_IS_LITERAL,所以代码会是

template <typename T> struct is_literal_type : integral_constant<bool,
    is_scalar<typename remove_all_extents<T>::type>::value or
    is_reference<typename remove_all_extents<T>::type>::value> {};

我写了一个demo:

#include <iostream>

using namespace std;
struct s {
    int a;
    char b;
    long c;
};
int main(int argc, char *argv[]) {
    cout << boolalpha;
    cout << is_scalar_v<typename remove_all_extents<s>::type> << endl;
    cout << is_reference_v<typename remove_all_extents<s>::type> << endl;
}

结果为falsefalse。但是 is_literal_type_v<s> 的结果是 true.

谁能解释一下 std::is_literal_type 是如何工作的?

is_literal_type 是一个 "magic" C++ 库。它 不能 在 C++ 中作为当前语言实现(使用静态反射,它应该是可能的,但那是最快的 C++23)。它是通过使用特定于编译器的内部工具来实现的,而不是直接使用 C++。 _LIBCPP_IS_LITERAL 可能是编译器定义的宏(因此它看起来未定义),它表示特定的编译器内在。

因此,您真的不应该太仔细地研究这个或许多其他类型特征的实现。

我认为未定义 _LIBCPP_IS_LITERAL 的版本是为了与未公开必要内在函数的旧版本编译器兼容。因此,库实现在没有编译器支持的情况下尽其所能。

添加@NicolBolas 之前的回答:未设置_LIBCPP_IS_LITERAL 可能是错误的。看看 __config.h:

#if defined(_LIBCPP_COMPILER_CLANG)

[...]

#if __has_feature(is_literal)
#define _LIBCPP_IS_LITERAL(T) __is_literal(T)
#endif

[...]

#elif defined(_LIBCPP_COMPILER_GCC)

[...]

#if _GNUC_VER >= 407
[...]
#define _LIBCPP_IS_LITERAL(T) __is_literal_type(T)
[...]
#endif

因此,如果您使用足够新的 Clang 或 GCC 进行编译,那么宏将被设置,并且在任何一种情况下,它都将使用编译器内部函数。 __is_literal 用于 Clang 或 __is_literal_type 用于 GCC。

两个内在函数都有记录:

来自https://clang.llvm.org/docs/LanguageExtensions.html

__is_literal(type): Determines whether the given type is a literal type

来自https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html

__is_literal_type (type)

If type is a literal type ([basic.types]) the trait is true, else it is false. Requires: type shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound.

不过您不应该直接使用这些内部函数,因为如您所见,它们不可移植。它们是为标准库开发人员定义的。