最近在看kdtree的东西找到一个只包含头文件的实现版,看到里面有这样一段代码一脸懵
template <typename T, typename = int> struct has_resize : std::false_type {};
查了一下才知道这个语句是一个用于进行模板元编程的定义。它定义了一个模板结构体 has_resize
,该结构体用于判断类型 T
是否拥有 resize
成员函数。
让我们逐步解释这个语句:
template <typename T, typename=int> struct has_resize : std::false_type {};
template <typename T, typename=int>
:这代表着这是一个模板结构体,并接受两个模板参数。第一个参数T
是待检查的类型,第二个参数int
是一个默认参数。struct has_resize : std::false_type {}
:这定义了一个结构体has_resize
,并继承自std::false_type
类。std::false_type
是一个标准库中的结构体,用于表示布尔值false
。
这段代码的作用是定义了 has_resize
结构体,并将其默认初始化为 std::false_type
,意味着默认情况下假设待检查的类型 T
不具有 resize
成员函数。
此时,我们可以使用特化(specialization)来对具体的类型进行判断。如果某个特定类型 T
拥有 resize
成员函数,那么可以创建一个非模板的 has_resize<T>
的部分特化版本,将其继承自 std::true_type
类,从而改变默认的 std::false_type
为 std::true_type
:
template <typename T> struct has_resize<T, decltype(std::declval<T>().resize(0), 0)> : std::true_type {};
这个部分特化的定义使用了 SFINAE(Substitution Failure Is Not An Error)机制来根据 T
的属性进行匹配。如果 T
类型在调用表达式 std::declval<T>().resize(0)
时能够通过编译,那么这个部分特化将生效,继承自 std::true_type
,表示类型 T
确实具有 resize
成员函数。
通过结合这两部分定义,我们可以在模板元编程中使用 has_resize<T>::value
来判断某个类型 T
是否支持 resize
成员函数。如果 has_resize<T>::value
为 true
,则表示类型 T
支持 resize
成员函数;如果为 false
,则表示不支持。
例如:
#include <iostream>
#include <type_traits>template <typename T, typename=int> struct has_resize : std::false_type {};template <typename T>
struct has_resize<T, decltype(std::declval<T>().resize(0), 0)> : std::true_type {};class Container {
public:void resize(int size) {std::cout << "Resizing container to size: " << size << std::endl; }
};class NoResizeContainer {// 没有 resize 成员函数
};int main() {std::cout << std::boolalpha;std::cout << has_resize<Container>::value << std::endl; // 输出 truestd::cout << has_resize<NoResizeContainer>::value << std::endl; // 输出 falsereturn 0;
}
在上述示例中,has_resize<Container>::value
的值为 true
,表示 Container
类型具有 resize
成员函数。而 has_resize<NoResizeContainer>::value
的值为 false
,表示 NoResizeContainer
类型不具有 resize
成员函数。
这种技术可以用于编写更加泛化和灵活的代码,根据类型的特性来进行条件判断和分发。