模板元编程常用函数

189 阅读4分钟

std::is_standard_layout

std::is_standard_layout 是 C++11 提供的一个 type traits,用来检查一个类型是否是标准布局的。标准布局的类型是满足以下所有条件的类型:

  • 所有非静态成员都是相同的访问权限(public/protected/private)
  • 所有非静态成员都没有虚函数、虚基类、非静态成员对象
  • 如果有基类,基类也是标准布局
  • 成员的顺序没有影响

如果一个类型是标准布局,那么它可以在 C 语言中使用,并且可以用于以下情况:

  • 序列化到文件或网络流
  • 内存映射文件
  • 在多个进程之间共享内存
  • 使用 memcpy 等函数进行快速复制或移动

可以使用 std::is_standard_layout<T> 来检查一个类型 T 是否是标准布局类型。如果是,它的 value 成员为 true,否则为 falsestd::is_standard_layout 可以在编译期确定,可以用于模板元编程中。

std::is_base_of

std::is_base_of<Base, Derived>::value 是一个 constexpr bool 类型的模板变量,用来判断 Derived 类型是否是 Base 类型的派生类。如果是,则 valuetrue,否则为 false

static_assert(
      std::is_base_of<Executor, ExecutorT>::value,
      "getKeepAliveToken only works for folly::Executor implementations.");

std::enable_if

std::enable_if 可以在模板实例化时根据模板参数的特性选择模板的某个版本,使得模板的特化程度更加准确,从而避免模板参数错误导致编译错误。 std::enable_if 的语法如下:

template <bool Cond, typename T = void>
struct enable_if {};

template <typename T>
struct enable_if<true, T> { using type = T; };

其中 Cond 为布尔类型,当 Cond 为 true 时,enable_if 的静态成员变量 typeT,否则不定义 type,这使得可以通过 enable_if 进行 SFINAE 技术,即 “Substitution Failure Is Not An Error”,它可以在编译期间进行一些判断和选择,如果判断不符合条件,则会在编译期间被排除,避免出现编译错误。

例如:

template <typename T>
typename std::enable_if<std::is_pointer<T>::value, void>::type
print(T t) {
  std::cout << *t << std::endl;
}

int main() {
  int a = 10;
  int* ptr = &a;
  print(ptr);  // 输出 10
  print(a);    // 编译错误,因为 a 不是指针类型
}

在上述代码中,std::enable_if 的第一个参数为 std::is_pointer<T>::value,当 T 是指针类型时,std::is_pointer<T>::valuetrue,此时 std::enable_iftypevoid,因此 print 函数的返回值类型为 void,否则 std::enable_iftype 不存在,该函数被排除在外,不会被实例化,从而避免了编译错误。

std::is_convertible

std::is_convertible 是一个 type trait(类型特征),用于判断给定的类型是否可以隐式转换为另一个类型。它的定义如下:


template <class From, class To>
struct is_convertible;

当类型 From 可以隐式转换为类型 To 时,std::is_convertible<From, To>::valuetrue,否则为 false。例如,当 FromintTodouble 时,std::is_convertible<From, To>::value 将会是 true,因为 int 可以隐式转换为 double。而当 From 是一个函数类型,而 To 是一个指向该函数类型的指针时,也会返回 true

在实际应用中,std::is_convertible 可以与其他 type trait 结合使用,例如 std::enable_if,用于限制函数模板的参数类型,以便只接受可以隐式转换为目标类型的参数类型。

std::is_same

用于在编译时比较两个类型是否相同。这对于模板编程中的类型检查、静态断言和条件编译非常有用

constexpr bool kAlreadyChecked = std::is_same<KeyT, LookupKeyTNoConst>::value;
 if (!kAlreadyChecked) {
  checkLegalKeyIfKey(key_new);
}             

decltype

decltype 是 C++11 引入的一种关键字,用于查询表达式的类型。它可以在编译时确定变量、函数调用或表达式的类型,并使用该类型进行变量声明、模板参数推导等操作。decltype 提供了一种更简洁、灵活和强大的方式来获取类型信息。

// 1. 推导变量类型
int x = 5; 
decltype(x) y = 10; // y 的类型是 int

// 2. 推导表达式类型
int a = 10; 
decltype(a + 5) b = 15; // b 的类型是 int,因为 a + 5 的类型是 int

// 3. 推导函数调用返回值
int foo() { return 42; } 
decltype(foo()) result = foo(); // result 的类型是 int

// 4. 返回类型后置语法中
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u) { 
   return t + u; 
}