c++ template std::void_t 是个啥

源码

<type_traits>头文件里有void_t的定义

template <class... _Types>
using void_t = void;

很简单,其实就是void,只不过可以传入模板参数,比如std::void_t<int, float, double>,但归根到底他还是void

有什么用

那他有啥用,看上去像是一段无用的程序
这里就用到SFINAE(Substitution failure is not an error)的知识了,我们分三步走

  • 先看这个问题: 下面有三种foo函数,称其为Foo0,Foo1,Foo2,请问 foo foo foo 分别匹配到了哪个函数?

    struct X {
      typedef int type;
    };
    
    struct Y {
      typedef int type2;
    };
    
    template <typename T> void foo(typename T::type);    // Foo0
    template <typename T> void foo(typename T::type2);   // Foo1
    template <typename T> void foo(T);                   // Foo2
    
    foo<X>(5);    // Foo0: Succeed, Foo1: Failed,  Foo2: Failed
    foo<Y>(10);   // Foo0: Failed,  Foo1: Succeed, Foo2: Failed
    foo<int>(15); // Foo0: Failed,  Foo1: Failed,  Foo2: Succeed
    

    对于foo,因为X有type,所以直接匹配到了Foo0
    对于foo,因为Y没有typ,所以匹配Foo0失败,尝试匹配下一个,Y有type2,成功匹配到了Foo1
    对于foo,因为int既没有type有没有type2,所以Foo0和Foo1都匹配失败,最终匹配到了Foo2
    看到了吧,虽然有的地方匹配失败了,但是编译器并不会直接报错,他会尝试去匹配其他的

  • 回到std::void_t,通过上一点可知,我们对他的定义应该更严谨 : 如果传进来的模板参数是正常的,那std::void_t就是void;但是如果传进来的模板产生了错误,std::void_t会产生匹配错误,编译器您去找别人吧...

  • 将 SFINAE 和 std::void_t 结合,我们可以得到任意类型的不同匹配分支

    // primary template handles types that have no nested ::type member:
    template< class, class = void >
    struct has_type_member : std::false_type { };
     
    // specialization recognizes types that do have a nested ::type member:
    template< class T >
    struct has_type_member<T, std::void_t<typename T::type>> : std::true_type { };
    
    auto f = has_type_member<float>::value; // false
    auto x = has_type_member<X>::value; // true
    auto y = has_type_member<Y>::value; // false
    

    对于has_type_member<float>,因为float没有type,所以第二个模板会匹配失败,编译器会认为现在的has_type_member<float>实际是has_type_member<float, void>(因为void是个默认参数),进而成功匹配第一个模板
    对于has_type_member<X>,因为X有type,第二个模板直接匹配成功,编译器会认为这是第一个模板的一个特化版本
    这里std::void_t的作用,就是把传进来的各个类型进行一个检测,哦没错过了吧!诶不对传进来的有问题编译器你快过来看看!

实际使用

判断stream是否有operator<<

template <class T0, class T1, class = void>
struct _has_stream_bit_shl : std::false_type {};

template <class T0, class T1>
struct _has_stream_bit_shl<T0, T1, std::void_t<
	decltype(std::declval<T0>() << std::declval<T1>())
	>> : std::true_type {};

auto a = _has_stream_bit_shl<std::ostream&, const int&>::value; // true
auto b = _has_stream_bit_shl<std::ostream&, const X&>::value; // false

参考:c++ - How do we use void_t for SFINAE? - Stack Overflow

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
听说这个有用 The following are typedefs of fundamental integral types or extended integral types. signed type unsigned type description intmax_t uintmax_t Integer type with the maximum width supported. int8_t uint8_t Integer type with a width of exactly 8, 16, 32, or 64 bits. For signed types, negative values are represented using 2's complement. No padding bits. Optional: These typedefs are not defined if no types with such characteristics exist.* int16_t uint16_t int32_t uint32_t int64_t uint64_t int_least8_t uint_least8_t Integer type with a minimum of 8, 16, 32, or 64 bits. No other integer type exists with lesser size and at least the specified width. int_least16_t uint_least16_t int_least32_t uint_least32_t int_least64_t uint_least64_t int_fast8_t uint_fast8_t Integer type with a minimum of 8, 16, 32, or 64 bits. At least as fast as any other integer type with at least the specified width. int_fast16_t uint_fast16_t int_fast32_t uint_fast32_t int_fast64_t uint_fast64_t intptr_t uintptr_t Integer type capable of holding a value converted from a void pointer and then be converted back to that type with a value that compares equal to the original pointer. Optional: These typedefs may not be defined in some library implementations.* Some of these typedefs may denote the same types. Therefore, function overloads should not rely on these being different. * Notice that some types are optional (and thus, with no portability guarantees). A particular library implementation may also define additional types with other widths supported by its system. In any case, if either the signed or the unsigned version is defined, both the signed and unsigned versions are defined.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值