简体   繁体   English

检查类T是否具有成员类型成员void_t

[英]Checking if class T has member type Member with void_t

So here's the code: 所以这是代码:

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;
}

I'm trying to check whether foo has a bar type member. 我正在尝试检查foo是否有bar成员。 It works fine if the implementation doesn't specify the type member's name, but that way the name is hardcoded into the implementation, which doesn't work for me. 如果实现没有指定类型成员的名称,它工作正常,但这样的名称硬编码到实现中,这对我不起作用。

The question said to be duplicate doesn't come close to answering my question. 说复制的问题并没有接近回答我的问题。 As I explained in the paragraph above, it's fine when the type is hardcoded into the implementation, but I can't get it to work when I specify the type from outside (that's the specific problem). 正如我在上面的段落中所解释的那样,当类型被硬编码到实现中时,它很好,但是当我从外部指定类型时,我无法使它工作(这是特定的问题)。 The code compiles fine, but produces wrong results. 代码编译良好,但产生错误的结果。

Your code doesn't work because typename foo::bar just directly resolves to int , rather than passing in some construct you can use for SFINAE. 你的代码不起作用,因为typename foo::bar只是直接解析为int ,而不是传入一些你可以用于SFINAE的构造。

A possible solution is to make an alias template which will tell you what the type of T::bar is, then pass that into your checker. 一个可能的解决方案是创建一个别名模板,它将告诉你T::bar的类型,然后将其传递给你的检查器。 This is what std::experimental::is_detected does. 这就是std::experimental::is_detected作用。 Here is a simplified version which is close to what you had already*: 这是一个简化的版本,接近你已经*:

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 {};

Then you write your alias template which you want to detect: 然后编写要检测的别名模板:

template <typename T> using bar_t = typename T::bar;

And usage looks like this: 用法如下:

is_detected <foo, bar_t>::value

*: I kept the template parameters the same way around as in your sample code so that you can easily compare. *:我保持模板参数的方式与示例代码相同,以便您可以轻松比较。 Flipping them around so that you can make the operator arguments variadic is better in a more generic context. 翻转它们以便在更通用的上下文中使操作符参数变量更好。 It would also make it easier to migrate to std::experimental::is_detected when available for you. 它也可以让你更容易迁移到std::experimental::is_detected

Once N4487 gets accepted, you'll be able to employ generic lambdas in constant expressions: 一旦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 with cout . cout 演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM