C++ 元编程检查类型是否存在

问题描述 投票:0回答:1

下面的源代码摘自MongoDB。

我理解

detect_clone_factory_type_member_impl
的目的是检查类型
T
是否拥有
clone_factory_type
。然而,令我困惑的是,由于
Derived
继承自
T
Fallback
,无论
T
是否有
clone_factory_type
Derived
都应该拥有
clone_factory_type
。这是否意味着应该始终选择第一个测试函数
No& test(typename U::clone_factory_type*)

当我实际进行实验时,这个例程按预期工作,这让我很好奇这个机制是如何运作的。我很欣赏各种专业人士的专业知识。

template <typename T>
struct detect_clone_factory_type_member_impl {
    struct Fallback {
        struct clone_factory_type {};
    };

    struct Derived : T, Fallback {};

    using Yes = char[2];
    using No = char[1];

    template <typename U>
    static No& test(typename U::clone_factory_type*);

    template <typename U>
    static Yes& test(U*);

    static constexpr bool value = sizeof(test<Derived>(nullptr)) == sizeof(Yes);

    using type = typename std::integral_constant<bool, value>::type;
};
c++ metaprogramming
1个回答
0
投票

这是 C++ 模板元编程中 SFINAE(替换失败不是错误)的经典示例。让我们分解一下代码的工作原理:

定义了主模板“detect_clone_factory_type_member_impl”,其中包含一个嵌套结构 Fallback 以及一个内部结构“clone_factory_type”。

在'detect_clone_factory_type_member_impl'内部,定义了另一个嵌套结构Derived,它继承自T和Fallback。

定义了两个使用别名,Yes 和 No。 Yes 是一个大小为 2 的数组,而 No 是一个大小为 1 的数组。

定义了两个名为test的重载静态成员函数:

一个版本采用指向类型 typename U::clone_factory_type* 的指针作为参数。 另一个版本采用指向任何类型 U* 的指针作为参数。 测试函数分别返回对 Yes 和 No 的引用。

定义了一个静态constexpr布尔变量值,通过调用sizeof(test(nullptr)) == sizeof(Yes)来初始化。这将检查 Derived 测试的重载决策是否成功。

类型别名定义为 std::integral_constant::type,它将生成的布尔值作为类型。

现在,让我们考虑一下调用 test(nullptr) 时重载决策期间会发生什么:

如果 T 有一个嵌套类型clone_factory_type,那么 test 的第一次重载将是更好的匹配,因为 typename U::clone_factory_type* 比 U* 更好的匹配。因此,sizeof(test(nullptr)) 将等于 sizeof(Yes)。

如果T没有嵌套类型clone_factory_type,那么第一次重载的test将会因为SFINAE(Substitution Failure Is Not An Error)而被丢弃。在这种情况下,将选择 test 的第二个重载,并且 sizeof(test(nullptr)) 将等于 sizeof(No)。

根据sizeof(test(nullptr))的结果,设置value的值,判断T是否有嵌套类型clone_factory_type。

总而言之,这种机制允许编译器根据T是否具有嵌套类型clone_factory_type,使用SFINAE来选择测试函数的适当重载。

希望这对您有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.