#include <iostream>
template <typename T>
struct CheckX
{
using TypeOfX = decltype(T::x);
using Value = void;
};
struct A
{
};
struct B
{
int x;
};
template <typename T , typename = void>
struct Res
{
static constexpr bool value = false;
};
// template <typename T>
// struct Res<T , std::void_t<decltype(T::x)>>
// {
// static constexpr bool value = true;
// };
template <typename T>
struct Res<T , typename CheckX<T>::Value>
{
static constexpr bool value = true;
};
int main()
{
std::cout << Res<B>::value << '\n';
std::cout << Res<A>::value << '\n';
}
这些是我想要实现一个检查器的代码,该检查器检查结构中是否存在成员
x
。我注意到使用自定义 CheckX
会导致编译失败,而 std 库 std::void_t
会完成这项工作。我在这里缺少什么?
第一个版本(带有
void_t
)完全按照您的预期工作:A
,当考虑此 std::void_t<decltype(T::x)>
时,A::x
会导致替换失败(由于缺少 Res
)。Res
被丢弃,留下默认的 Res
和 value = false
。
第二个版本(带有
CheckX<T>
)甚至没有进入SFINAE阶段Res
:CheckX<T>::Value
,首先将 CheckX<T>
实例化。作为其中的一部分,using TypeOfX = decltype(T::x)
被解析,并且由于A
不包含x
,decltype(T::x)
会触发错误。using
的这个 A
声明不是 Res
的 SFINAE 的一部分(它是在初步阶段完成的)。
std::void_t
的确切目的:
将任何类型的序列映射到该类型的实用程序元函数 空白。 此元函数是利用 SFINAE 先验的便捷方法 C++20 的概念,特别是有条件删除 根据表达式是否为候选集的函数 在未评估的上下文中有效(例如 decltype 的操作数 表达式),允许存在单独的函数重载或 基于支持的操作的专业化。
(重点是我的)
另请参阅
cppreference.com 页面中的
struct has_type_member
示例。