std::enable_if

来自cppreference.com
< cpp‎ | types
 
 
工具库
类型支持(基本类型、 RTTI 、类型特性)
动态内存管理
错误处理
程序工具
变参数函数
日期和时间
函数对象
(C++11)
关系运算符
optionalanyvariant (C++17)
pair 与 tuple
(C++11)
(C++17)
swap 、 forward 与 move
(C++14)
(C++11)
(C++11)
初等字符串转换
(C++17)
(C++17)
类型运算
(C++11)
(C++17)
 
类型支持
基本类型
基础类型
定宽整数类型 (C++11)
数值极限
C 数值极限接口
运行时类型信息
类型特性
类型类别
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
类型属性
(C++11)
(C++11)
(C++11)
(C++14)
(C++11)
(C++11)(C++17中过时)
(C++11)
类型特性常量
元函数
(C++17)
端序
(C++20)
受支持操作
关系与属性查询
(C++11)
(C++11)
(C++11)
(C++11)
类型修改
(C++11)
(C++11)
(C++11)
类型变换
(C++11)
enable_if
(C++11)
(C++17)
(C++11)(C++17中过时)
(C++17)
 
定义于头文件 <type_traits>
template< bool B, class T = void >
struct enable_if;
(C++11 起)

Btrue ,则 std::enable_if 拥有公开成员 typedef type ,等于 T ;否则,无该成员 typedef 。

此元函数是活用 SFINAE ,基于类型特性条件性地从重载决议移除函数,并对不同类型特性提供分离的函数重载与特化的便利方法。 std::enable_if 可用作额外的函数参数(不可应用于运算符重载)、返回类型(不可应用于构造函数与析构函数),或类模板或函数模板形参。

目录

[编辑] 成员类型

类型 定义
type 依赖 B 的值,为 T 或无此成员

[编辑] 帮助类型

template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type;
(C++14 起)

[编辑] 可能的实现

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

[编辑] 注意

常见错误是声明二个函数模板,而它们仅于其默认模板实参相异。此乃非法,因为默认模板实参不是函数模板签名的一部分,而且声明二个拥有同一签名的不同函数模板是非法的。

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) {}
 
    template <typename Floating,
              typename = std::enable_if_t<std::is_floating_point<Floating>::value>
    >
    T(Floating) : m_type(float_t) {} // 错误:不能重载
};

于命名空间函数模板作用域的模板非类型形参中使用 enable_if 时需留意。某些 ABI 规范,如 Itanium ABI ,不于重整中包含非类型模板形参的实例化依赖部分。这表示二个相异的函数模板特化可能以相同重整名归纳,并且错误地相互链接。例如:

// 第一个翻译单元
 
struct X {
    enum { value1 = true, value2 = true };
};
 
template<class T, std::enable_if_t<T::value1, int> = 0>
void func() {} // #1
 
template void func<X>(); // #2
 
// 第二个翻译单元
 
struct X {
    enum { value1 = true, value2 = true };
};
 
template<class T, std::enable_if_t<T::value2, int> = 0>
void func() {} // #3
 
template void func<X>(); //#4

函数模板 #1 与 #3 拥有不同签名,且为不同的模板。不过 #2 与 #4 尽管是不同函数模板的实例化,却于 Itanium C++ ABI 拥有相同的重整名( _Z4funcI1XLi0EEvv ),这表示链接器会错误地认为它们是同一实体。

[编辑] 示例

#include <type_traits>
#include <iostream>
#include <string>
 
namespace detail { struct inplace_t{}; }
void* operator new(std::size_t, void* p, detail::inplace_t) {
    return p;
}
 
// #1 ,通过返回类型使用
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";
}
 
// #2
template<class T, class... Args>
std::enable_if_t<!std::is_trivially_constructible<T,Args&&...>::value> // 使用帮助类型
    construct(T* t,Args&&... args) 
{
    std::cout << "constructing non-trivially constructible T\n";
    new(t, detail::inplace_t{}) T(args...);
}
 
// #3 ,通过形参启用
template<class T>
void destroy(T* t, 
             typename std::enable_if<std::is_trivially_destructible<T>::value>::type* = 0) 
{
    std::cout << "destroying trivially destructible T\n";
}
 
// #4 ,通过模板形参启用
template<class T,
         typename std::enable_if<
             !std::is_trivially_destructible<T>{} &&
             (std::is_class<T>{} || std::is_union<T>{}),
            int>::type = 0>
void destroy(T* t)
{
    std::cout << "destroying non-trivially destructible T\n";
    t->~T();
}
 
// #5 ,通过模板形参启用
template<class T,
	typename = std::enable_if_t<std::is_array<T>::value> >
void destroy(T* t) // 注意,不修改函数签名
{
    for(std::size_t i = 0; i < std::extent<T>::value; ++i) {
        destroy((*t)[i]);
    }
}
/*
template<class T,
	typename = std::enable_if_t<std::is_void<T>::value> >
void destroy(T* t){} // 错误:与 #5 拥有相同签名
*/
 
// A 的部分特化通过模板形参启用
template<class T, class Enable = void>
class A {}; // 初等模板
 
template<class T>
class A<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
}; // 为浮点类型特化
 
int main()
{
    std::aligned_union_t<0,int,std::string> u;
 
    construct(reinterpret_cast<int*>(&u));
    destroy(reinterpret_cast<int*>(&u));
 
    construct(reinterpret_cast<std::string*>(&u),"Hello");
    destroy(reinterpret_cast<std::string*>(&u));
 
    A<int> a1; // OK ,匹配初等模板
    A<double> a2; // OK ,匹配部分特化
}

输出:

constructing trivially constructible T
destroying trivially destructible T
constructing non-trivially constructible T
destroying non-trivially destructible T

[编辑] 参阅

(C++17)
void 变参数别名模板
(别名模板) [编辑]