检查 class T 是否具有 void_t 的成员类型 Member
Checking if class T has member type Member with void_t
代码如下:
template<typename, typename, typename = void>
struct has_member_type : false_type {};
template<typename T, typename Member>
struct has_member_type<T, Member, void_t<typename T::Member>> : true_type {};
struct foo { using bar = int; };
int main()
{
std::cout << has_member_type<foo, typename foo::bar>::value;
}
我正在尝试检查 foo
是否有 bar
类型的成员。如果实现不指定类型成员的名称,它工作正常,但这样名称被硬编码到实现中,这对我不起作用。
据说是重复的问题并没有回答我的问题。正如我在上面的段落中解释的那样,当类型被硬编码到实现中时它很好,但是当我从外部指定类型时我无法让它工作(这是特定问题)。代码编译正常,但产生错误的结果。
您的代码不起作用,因为 typename foo::bar
只是直接解析为 int
,而不是传入可用于 SFINAE 的某些结构。
一个可能的解决方案是制作一个别名模板,它将告诉您 T::bar
的类型,然后将其传递给您的检查器。这就是 std::experimental::is_detected
所做的。这是一个简化版本,与您已经拥有的版本接近*:
template<typename, template <typename> class, typename = void>
struct is_detected : false_type {};
template<typename T, template <typename> class Op>
struct is_detected<T, Op, void_t<Op<T>>> : true_type {};
然后编写要检测的别名模板:
template <typename T> using bar_t = typename T::bar;
用法如下:
is_detected <foo, bar_t>::value
*:我将模板参数与您的示例代码中的模板参数保持一致,以便您可以轻松进行比较。在更通用的上下文中翻转它们以便使运算符参数可变更好。它还可以让您更轻松地迁移到 std::experimental::is_detected
可用时。
一旦 N4487 被接受,您将能够在常量表达式中使用通用 lambda:
template <typename T, typename F>
constexpr auto test(F f) -> decltype(f(std::declval<T&>()), true) {return true;}
template <typename, typename... F>
constexpr bool test(F...) {return false;}
#define HAS_DATA(Name, ...) (test<__VA_ARGS__>([] (auto& t) -> decltype(&std::decay_t<decltype(t)>::Name) {}))
#define HAS_TYPE(Name, ...) (test<__VA_ARGS__>([] (auto& t) -> typename std::decay_t<decltype(t)>::Name {}))
Demo 与 cout
.
代码如下:
template<typename, typename, typename = void>
struct has_member_type : false_type {};
template<typename T, typename Member>
struct has_member_type<T, Member, void_t<typename T::Member>> : true_type {};
struct foo { using bar = int; };
int main()
{
std::cout << has_member_type<foo, typename foo::bar>::value;
}
我正在尝试检查 foo
是否有 bar
类型的成员。如果实现不指定类型成员的名称,它工作正常,但这样名称被硬编码到实现中,这对我不起作用。
据说是重复的问题并没有回答我的问题。正如我在上面的段落中解释的那样,当类型被硬编码到实现中时它很好,但是当我从外部指定类型时我无法让它工作(这是特定问题)。代码编译正常,但产生错误的结果。
您的代码不起作用,因为 typename foo::bar
只是直接解析为 int
,而不是传入可用于 SFINAE 的某些结构。
一个可能的解决方案是制作一个别名模板,它将告诉您 T::bar
的类型,然后将其传递给您的检查器。这就是 std::experimental::is_detected
所做的。这是一个简化版本,与您已经拥有的版本接近*:
template<typename, template <typename> class, typename = void>
struct is_detected : false_type {};
template<typename T, template <typename> class Op>
struct is_detected<T, Op, void_t<Op<T>>> : true_type {};
然后编写要检测的别名模板:
template <typename T> using bar_t = typename T::bar;
用法如下:
is_detected <foo, bar_t>::value
*:我将模板参数与您的示例代码中的模板参数保持一致,以便您可以轻松进行比较。在更通用的上下文中翻转它们以便使运算符参数可变更好。它还可以让您更轻松地迁移到 std::experimental::is_detected
可用时。
一旦 N4487 被接受,您将能够在常量表达式中使用通用 lambda:
template <typename T, typename F>
constexpr auto test(F f) -> decltype(f(std::declval<T&>()), true) {return true;}
template <typename, typename... F>
constexpr bool test(F...) {return false;}
#define HAS_DATA(Name, ...) (test<__VA_ARGS__>([] (auto& t) -> decltype(&std::decay_t<decltype(t)>::Name) {}))
#define HAS_TYPE(Name, ...) (test<__VA_ARGS__>([] (auto& t) -> typename std::decay_t<decltype(t)>::Name {}))
Demo 与 cout
.