模板编程简介-基础
本文内容来自极客时光的 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