C++编程实践—false_type和true_type的实践应用

一、说明

c++标准中提供了元编程接口std::integral_constant,而在这个接口中又提供了针对bool类型的两个实例化类型:

c 复制代码
true_type 	std::integral_constant<bool, true>
false_type 	std::integral_constant<bool, false>

在前面的文章分析中,特别是针对std::index_sequence的相关文章中,对其进行过介绍。另外在分析其它模板和元编程的过程中,也对它们进行过顺便的应用说明。但对它们的应用并没有系统性的说明。本文将针对其实际应用的方式进行整体的总结说明。

二、应用形式

在模板或元编程中,true_type和false_type基本有两种应用形式:

  1. 用作基类
    这种是最典型的情况,比如前面的成员检测:
c 复制代码
template<typename T, typename = void>
struct checkSize : std::false_type {};

template<typename T>
struct checkSize<T, std::void_t<decltype(std::declval<T>().size())>> : std::true_type {};

而在元编程库中的很多接口都继承自它们,比如std::is_pointer等:

c 复制代码
template<class T>
struct is_pointer : std::false_type {};
template<class T>
struct is_pointer<T*> : std::true_type {};
template<class T>
struct is_pointer<T* const> : std::true_type {};
template<class T>
struct is_pointer<T* volatile> : std::true_type {};
template<class T>
struct is_pointer<T* const volatile> : std::true_type {};

在实际的开发中,这种情况也是非常常见的。

  1. 标签分发处理
    这种情况主要有函数重载处理、静态断言和条件编译:
c 复制代码
#include <iostream>
#include <type_traits>
#include <utility>
struct CopyType {};

struct MoveType {
  MoveType() = default;
  MoveType(const MoveType &) = delete;
  MoveType(MoveType &&) = default;  
};

template <typename T> void testFunc(T value, std::true_type ) {
  std::cout << "call copy!" << std::endl;
}

template <typename T> void testFunc(T value, std::false_type )  {
  std::cout << "call move!" << std::endl;
}

template <typename T> void process(T value) {
  testFunc(std::forward<T>(value), std::is_copy_constructible<T>{});
}

int main() {
  CopyType ct;
  process(ct);

  MoveType nct;
  process(std::move(nct)); 
  return 0;
}

其它的实现也都类似,不再过多列举。

三、实现方法

std::false_type和std::true_type是从std::integral_constant扩展而来的,所以需要看integral_constant具体的实现:

c 复制代码
template<class T, T v>
struct integral_constant
{
    static constexpr T value = v;
    using value_type = T;
    using type = integral_constant; // using injected-class-name
    constexpr operator value_type() const noexcept { return value; }
    constexpr value_type operator()() const noexcept { return value; } // since c++14
};
template< bool B >
using bool_constant = integral_constant<bool, B>;

using true_type = integral_constant<bool, true>; 
using false_type =integral_constant<bool, false>;

大家可以尝试着用不同的方式来实现并进行工程验证。

四、例程

下面给出一个例程供大家分析:

c 复制代码
#include <iostream>
#include <type_traits>

// 正确转换函数
template <typename F, typename T> 
void castType(const F &from, T &to, std::true_type) {
  to = static_cast<T>(from);
    std::cout << "cast ok!" << std::endl;
}
//错误处理函数
template <typename F, typename T> 
void castType(const F &from, T &to, std::false_type) {
  static_assert(std::is_convertible<F, T>::value, "convertible result");
  std::cout << "cast error" << std::endl;
}

template <typename F, typename T> 
void castCheckRun(const F &from, T &to) { 
   castType(from, to, std::is_convertible<F, T>{}); 
}

int main() {
  int d = 1;
  double dd = 0.0;
  std::string str = "abc";
  castCheckRun(d, dd); 
  //castCheckRun(d, str); //error
  return 0;
}

再看一下std::is_function的源码实现:

c 复制代码
template<class>
struct is_function : std::false_type {};
 
// specialization for regular functions
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : std::true_type {};
 
// specialization for variadic functions such as std::printf
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : std::true_type {};
 
// specialization for function types that have cv-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) const> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile> : std::true_type {};
 
// specialization for function types that have ref-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &&> : std::true_type {};
 
// specializations for noexcept versions of all the above (C++17 and later)
template<class Ret, class... Args>
struct is_function<Ret(Args...) noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile && noexcept> : std::true_type {};

std::is_function处理的原理基本是函数类型(对象)不能有cv限定符且不能绑定到非const的左值引用(可绑定到const的左传引用或右值引用)。当然实际应用时一般是使用函数在地址转换时会隐式的转为函数指针。不过看上面的代码可以发现,其实为了编译处理更简单,就是靠量大管饱,大量特化相关的函数判断即可。

也可以这样理解,通过模板偏特化(partial specialization)列出可能的全部函数类型签名形式,对合法的函数类型进行std::true_type特化;其它由非函数类型则由匹配主模板,特化为 std::false_type。

五、总结

元编程和模板编程的复杂是大家公认的,但只要大家从基础的知识点出发,将不同的基础知识灵活运用起来,再加上多看网上开源的好的工程代码,就能够较快的掌握元编程和模板编程的技术。与诸君共勉!

相关推荐
量子炒饭大师2 小时前
Cyber骇客神经塔尖协议 ——【初阶数据结构与算法】堆
c语言·数据结构·c++·二叉树·github·
王老师青少年编程3 小时前
2025年12月GESP(C++二级): 环保能量球
c++·算法·gesp·csp·信奥赛·二级·环保能量球
CoderCodingNo3 小时前
【GESP】C++五级真题(贪心思想考点) luogu-P11960 [GESP202503 五级] 平均分配
开发语言·c++·算法
不会写代码的里奇4 小时前
深入解析ASR技术:从原理到C++高性能实现
c++
CSDN_RTKLIB4 小时前
【类定义系列六】C++17新特性
开发语言·c++
hd51cc4 小时前
MFC文件操作
c++·mfc
春蕾夏荷_7282977255 小时前
Sockets-2.3.9.9 UDP使用实例
c++·udp
GetcharZp6 小时前
拒绝硬编码!C++ 配置文件管理神器 yaml-cpp 实战指南
c++
墨有6666 小时前
C++ string 部分功能详解:迭代器、初始化与常用函数
开发语言·c++