C++模板元编程简介-sfinae基础知识

 2024-02-18 03:02:47  阅读 0

模板编程简介-基础

本文内容来自极客时光的 30 场现代 C++ 实践讲座。 这是我个人对内容的理解。

基本定义

template <typename T>
void f(typename T::foo) {
    
}
template <typename T>
void f( T) {
}

在这个例子中,如果T没有foo,当没有时,会直接编译错误,因为扩展结果是非法的。 不过,因为现在有了第一次扩展,发现不合法,所以编译错误不会立即出现,而是会尝试其他方法。 超载的扩展。

这是 的基本定义。

编译时成员检测

我们需要检测该类是否具有类型的对象。 我们可以写一个对象,代码如下

template <typename T>
struct has_reserve {
    struct good {char dummy;};
    struct bad{   char dummy[2]; };
    template <class U, void (U::*) (size_t)>  
    struct SFINAE{};
    template <class U>
    static good reserve(SFINAE<U, &U::reserve>*)
    template <class U>
    static bad reserve(...);
    static const bool vallue = sizeof(reserve<T>(nullptr) == sizeof(good))
};

其逻辑是,如果T型满足要求,就会选择好的过载。 如果不是,则将选择不良过载。 value的值可以在编译时根据类型大小的差异来确定。

用于防止膨胀

这可以用来实现编译时阻塞

它看起来像这样:

template <typename C, typename T>
enable_if_t<has_reserve<C>::value,
            void>
append(C& container, T* ptr,
       size_t size)
{
  container.reserve(
    container.size() + size);
    ...
}
template <typename C, typename T>
enable_if_thas_reserve<C>::value,
            void>
append(C& container, T* ptr,
       size_t size)
{
    ....
}

其实现原理:

首次实施

template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type;

获得了一个类型字段,也就是说,如果他可以模板扩展,他可以获得一个值,该值是一个类型,

那么实现就很明显了:

成功后,专攻

template<class T>
struct enable_if<true, T> { typedef T type; };

展开根据. 类型为T型。

当失败时:

template<bool B, class T = void>
struct enable_if {};

没有该字段,会影响模板的扩展和触发机制,并尝试下一次扩展。

使用标签分发

定义是这样的。

template <typename...>
using void_t = void;

这个看似无用的模板是为了诱导编译器检查表单T的合法性并使用该机制。

template <typename T,
          typename = void_t<>>
struct has_reserve : false_type {};
template <typename T>
struct has_reserve<
  T, void_t<decltype(
       declval<T&>().reserve(1U))>>
  : true_type {};

这里解释一下,这个东西是在没有默认构造函数的情况下使用的,所以你可以假装就是这个了,

我们会在这里检查是否有满足要求的东西。

declval<T&>().reserve(1U)

如果没有,根据原理,不会报编译错误,而是继续尝试其他扩展。 它变成了一个

有了这个机制,我们就可以使用简单的函数重载来实现如下代码

template <typename C, typename T>
void _append(C& container, T* ptr,
             size_t size,
             true_type)
{
    ....
}
template <typename C, typename T>
void _append(C& container, T* ptr,
             size_t size,
             false_type)
{
    ....
}
template <typename C, typename T>
void append(C& container, T* ptr,
            size_t size)
{
  _append(
    container, ptr, size,
    integral_constant<
      bool,
      has_reserve<C>::value>{});
}

使用 if 进行编译时 if

在cpp中,我们不能写下面的代码

template <typename C, typename T>
void append(C& container, T* ptr,
            size_t size)
{
  if (has_reserve<C>::value) {
    container.reserve(
      container.size() + size);
  }
}

这是运行时代码。 不行,这个会通过编译器的类型检查来检查,直接报错...

template <typename C, typename T>
void append(C& container, T* ptr,
            size_t size)
{
  if constexp (has_reserve<C>::value) {
    container.reserve(
      container.size() + size);
  }
}

可以用下面的方法,把这个if变成编译时判断,根据不同的调整,扩展不同的代码。 这种方法的可读性比以前好很多。

总结

[1]。 现代 C++30 讲座://intro/256?code=X8A%3D

标签: 展开 合法 入门

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码