C++模板元编程(三)——类型萃取

类型萃取(type_traits)是一种编译时技术,用于在编译期间获取和操作类型的信息,主要用于泛型编程以及在编译时做出决策。



常见的类型萃取

在C++11的<type_traits>头文件中,包含许多内置的类型萃取:

  1. std::is_integral<T>: 判断类型 T 是否为整型
  2. std::is_floating_point<T>: 判断类型 T 是否为浮点数类型
  3. std::is_pointer<T>: 判断类型 T 是否为指针类型
  4. std::is_reference<T>:判断类型 T 是否为引用类型
  5. std::is_const<T>:判断类型 T 是否为 const 类型
  6. std::is_same<T, U>:判断类型 TU 是否相同

这些类型萃取通常有一个静态布尔值 value,当类型符合特定条件时,它为 true 反之为 false

<xtr1common> 中也有一些内置的类型萃取:

  1. std::remove_reference_t<T> 移除类型 T 的左值引用/右值引用
  2. std::remove_cv_t<T> 移除类型 T 的常量符号
  3. std::enable_if_t<_Test, T> 如果_Test为真才有类型 T

内部实现

下面以 std::is_integral<T>std::enable_if_t<_Test, T> 为例看下它们的具体实现。

std::is_integral<T>

_EXPORT_STD template <class _Ty>
struct is_integral : bool_constant<is_integral_v<_Ty>> {};

可见其继承于 bool_constant<is_integral_v<_Ty>>,因此 typeboolvalue 是对应的布尔值
先看下 is_integral_v<_Ty>

_EXPORT_STD template <class _Ty>
_INLINE_VAR constexpr bool is_integral_v = _Is_any_of_v<remove_cv_t<_Ty>, bool, char, signed char, unsigned char,
    wchar_t,
#ifdef __cpp_char8_t
    char8_t,
#endif // __cpp_char8_t
    char16_t, char32_t, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long>;

remove_cv_t<_Ty> 移除 constvolatile 标识符

_Is_any_of_v<class _Ty, class... _Types> 如果是这些类型之一返回 true 否则返回 false,具体实现如下:

template <class _Ty, class... _Types>
_INLINE_VAR constexpr bool _Is_any_of_v = // true if and only if _Ty is in _Types
    disjunction_v<is_same<_Ty, _Types>...>;

这里的 is_same<_Ty, _Types>... 是参数包展开,创建了一系列的 is_same<T,U>
看下 is_same<T,U> 实现,其继承于 bool_constant<is_same_v<_Ty1, _Ty2>>

_EXPORT_STD template <class, class>
_INLINE_VAR constexpr bool is_same_v = false; // determine whether arguments are the same type
template <class _Ty>
_INLINE_VAR constexpr bool is_same_v<_Ty, _Ty> = true;

_EXPORT_STD template <class _Ty1, class _Ty2>
struct is_same : bool_constant<is_same_v<_Ty1, _Ty2>> {};

is_same_v 可以看到当传入的是相同的类型就是 true,不同类型就是 false
bool_constant<bool _Val> 其本身是一个bool类型的整型常量,所以is_same如果类型是相等的话,就是值为 true 的一个整型常量

_EXPORT_STD template <class _Ty, _Ty _Val>
struct integral_constant {
    static constexpr _Ty value = _Val;

    using value_type = _Ty;
    using type       = integral_constant;

    constexpr operator value_type() const noexcept {
        return value;
    }

    _NODISCARD constexpr value_type operator()() const noexcept {
        return value;
    }
};

_EXPORT_STD template <bool _Val>
using bool_constant = integral_constant<bool, _Val>;

_EXPORT_STD using true_type  = bool_constant<true>;
_EXPORT_STD using false_type = bool_constant<false>;

再看下 disjunction_v<class... _Traits>

template <bool _First_value, class _First, class... _Rest>
struct _Disjunction { // handle true trait or last trait
    using type = _First;
};

template <class _False, class _Next, class... _Rest>
struct _Disjunction<false, _False, _Next, _Rest...> { // first trait is false, try the next trait
    using type = typename _Disjunction<_Next::value, _Next, _Rest...>::type;
};

_EXPORT_STD template <class... _Traits>
struct disjunction : false_type {}; // If _Traits is empty, false_type

template <class _First, class... _Rest>
struct disjunction<_First, _Rest...> : _Disjunction<_First::value, _First, _Rest...>::type {
    // the first true trait in _Traits, or the last trait if none are true
};

_EXPORT_STD template <class... _Traits>
_INLINE_VAR constexpr bool disjunction_v = disjunction<_Traits...>::value;

当一个为true,就会终止展开,那么其实 disjunction_v 本身实现了一个或逻辑


std::enable_if_t<_Test, T>

它就是 enable_if<_Test, _Ty>::type

_EXPORT_STD template <bool _Test, class _Ty = void>
using enable_if_t = typename enable_if<_Test, _Ty>::type;

而其通过模板偏特化来实现,如果为 true 的话就有 type 否则没有 type

_EXPORT_STD template <bool _Test, class _Ty = void>
struct enable_if {}; // no member "type" when !_Test

template <class _Ty>
struct enable_if<true, _Ty> { // type is _Ty for _Test
    using type = _Ty;
};

应用

比如我们想要输出容器内的元素,对于有 const_iterator 的使用 const_iterator 否则使用 iterator

#include <iostream>
#include <vector>
#include <type_traits>

template <typename T>
struct has_const_iterator {
private:
	typedef char yes[1];
	typedef char no[2];

	template <typename C>
	static yes& test(typename C::const_iterator*);
	template <typename C>
	static no& test(...);
public:
	static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
};

template <typename Container>
typename std::enable_if<has_const_iterator<Container>::value>::type
print(const Container& c) {
	typename Container::const_iterator it;
	std::cout << "Using const_iterator." << std::endl;
	for (it = c.begin(); it != c.end(); ++it) {
		std::cout << *it << " ";
	}
	std::cout << std::endl;
}

template <typename Container>
typename std::enable_if<!has_const_iterator<Container>::value>::type
print(const Container& c) {
	typename Container::iterator it;
	std::cout << "Using iterator." << std::endl;
	for (it = c.begin(); it != c.end(); ++it) {
		std::cout << *it << " ";
	}
	std::cout << std::endl;
}

int main() {
	std::vector<int> v = { 1, 2, 3, 4, 5 };
	print(v);
}

这里 typename std::enable_if用来判断是否有 const_iterator,这是 SFINAE (Substitution Failure Is Not An Error),即模板特化失败就去掉而不是报错。

typename Container::iterator it 这是用来区分这是一个类型,而不是一个类的静态成员。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值