C++模板元编程中的一些函数特性【完善中】

1.std::enable_if

std::enable_if 顾名思义,满足条件时类型有效。它只有在第一个模板参数为true的时候才会定义type。

1.1 源码实现:

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

1.2 使用示例:

1.2.1 基本用法: 

typename std::enable_if<{BOOL 表达式}>::type

1.2.2 通过返回值使用:

对于模板函数,有时希望根据不同的模板参数返回不同类型的值,进而给函数模板也赋予类型模板特化的性质。典型的例子可以参看 tuple 的获取第 k 个元素的 get 函数。以下为另一种简单示例

template<class T,class... Args>
typename std::enable_if<std::is_trivially_constructible<T,Args&&...>::value>::type 
    construct(T* t,Args&&... args) 
{
    std::cout << "constructing trivially constructible T\n";
}

T和参数包...Args中的对象都是std::is_trivially_constructible时(即:可默认构造),std::enable_if的结果为void

1.2.3 通过模板函数参数使用

有时定义的模板函数,只希望特定的类型可以调用,此时在函数参数中使用enable_if

template<class T>
void destroy(
    T* t, //第一个参数
    typename std::enable_if< //第二个参数通过enable_if控制
        std::is_trivially_destructible<T>::value
    >::type* = 0)
{
    std::cout << "destroying trivially destructible T\n";
}

T的类型满足is_trivially_destructible的条件(即:可平凡析构),第二个参数的类型为void *并取默认值void* = 0

需要注意的是,这样操作后,函数的签名实际上变为了void destroy(T*, void*)。 这种操作的实质,是为了确保第一个参数是特定的类型(或满足特定的条件)。

常见错误
一个常见的错误是:声明了两个函数模板,它们只有默认模板实参不同

这是非法的,因为默认的模板实参不是函数模板签名的一部分,并且声明两个具有相同签名的不同函数模板是非法的。

/*** 错误典型 ***/
 
struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              typename = std::enable_if_t<std::is_integral<Integer>::value>
    >
    T(Integer) : m_type(int_t) {} //T<U, void>(U)
 
    template <typename Floating,
              typename = std::enable_if_t<std::is_floating_point<Floating>::value>
    >
    T(Floating) : m_type(float_t) {} // 错误:无法重载,因为其签名也是 T<U, void>(U)
};
 
/* 正确示例 */
 
struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              std::enable_if_t<std::is_integral<Integer>::value, int> = 0
    >
    T(Integer) : m_type(int_t) {} //仅当Integer为int时,签名为 T<int, int = 0>(int),否则SFINAE
 
    template <typename Floating,
              std::enable_if_t<std::is_floating_point<Floating>::value, int> = 0
    >
    T(Floating) : m_type(float_t) {} // 仅当Floating为浮点类型时,签名为,例如 T<double, int = 0>(double) 否则SFINAE
};



 


参考原文链接:https://blog.csdn.net/wbvalid/article/details/119352979

posted @ 2022-04-26 22:13  Clovran-Wong  阅读(125)  评论(0编辑  收藏  举报