检查 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 {}))

Democout.