std::模板类函数

模板类函数

1.01 std::is_floating_point

std::is_floating_point是C++11新增加的类型特征模板之一,它用于判断一个类型是否是浮点类型。它包含在头文件<type_traits>中。
通过在模板函数中使用std::is_floating_point来判断变量的类型是否是浮点类型,编写一个函数,用于处理两个浮点数的加法运算.

#include <iostream>
#include <type_traits>

template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
Add(T a, T b)
{
    return a + b;
}

int main()
{
    std::cout << Add(3.5, 4.2) << std::endl; // 输出7.7
    std::cout << Add(5, 6) << std::endl; // 编译错误,因为类型int不是浮点类型
}

1.02 std::is_object

用于判断一个类型是否是对象类型,即能够识别出是否为非class/struct/union类型。

#include<iostream>
#include<type_traits>

class MyClass{
public:
    void func(){};
};

int main(){
    std::cout << std::is_object<int>::value << std::endl; //true
    std::cout << std::is_object<MyClass>::value << std::endl; //true
    std::cout << std::is_object<int&>::value << std::endl; //false
    return 0;
}
1.03 std::is_union()

用于判断一个类型是否是联合体类型

#include <iostream>
#include <type_traits>

union MyUnion {
    int a;
    double b;
};

struct MyStruct {
    int a;
    double b;
};

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_union<MyUnion>::value << std::endl; // true
    std::cout << std::is_union<MyStruct>::value << std::endl; // false
    return 0;
}
1.04 std::is_assignable

用于检查一个类型是否能够被赋值。它通常用于编译时检查,以便在出现错误之前发现可能的问题。

std::is_assignable<type1, type2>::value

type1和type2是要检查的类型。返回值是一个bool值,如果type2可以被赋值给type1,则为true,否则为false。

#include <iostream>
#include <type_traits>

struct MyStruct {
    int x;
    int y;
};

int main() {
    std::cout << "int is assignable to int: " << std::is_assignable<int&, int>::value; //true
    return 0;
}
1.05 std::is_base_of

用来判断一个类是否是另一个类的基类

#include <iostream>
#include <type_traits>

class Base {};
class Derived : public Base {};

int main() {
    std::cout << std::boolalpha;
    std::cout << "Base is base of Derived: " << std::is_base_of<Base, Derived>::value << '\n';
    std::cout << "Derived is base of Base: " << std::is_base_of<Derived, Base>::value << '\n';
    return 0;
}
1.06 std::is_compound、std::is_fundamental

std::is_compound用于判断一个给定类型是否是复合类型(compound type),即除了内建类型(built-in type)外所有类型。
std::is_fundamental 用于判断一个给定类型是否内建类型。

#include <iostream>
#include <type_traits>

int main() {
  std::cout << std::is_compound<int>::value << std::endl; // 输出false
  std::cout << std::is_compound<int*>::value << std::endl; // 输出true
  
  std::cout << std::is_fundamental<int>::value << std::endl; // 输出true
  std::cout << std::is_fundamental<int*>::value << std::endl; // 输出false
  return 0;
}
1.07 std::is_constructible

一个类是否能够被构造,也就是是否存在其构造函数,是一个很重要的判断标准,也是模板库中很多算法和数据结构实现的基础。
只在编译期执行,检查结果不能在运行时改变,因为只有在编译期间,才有可能确定构造函数的相关信息。

#include <iostream>
#include <type_traits>

class MyType {
public:
    MyType(const int in_int, const double in_double) {}
    MyType(const MyType& other) {}
    MyType(MyType&& other) noexcept {}
};

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_constructible<MyType, int, double>::value << std::endl;  // true
    std::cout << std::is_constructible<MyType, MyType&>::value << std::endl;  // true
    std::cout << std::is_constructible<MyType, MyType&&>::value << std::endl;  // true
    std::cout << std::is_constructible<MyType>::value << std::endl;  // true
    std::cout << std::is_constructible<MyType, char*>::value << std::endl; // false
    return 0;
}
1.08 std::is_convertible

类型判断模板,第一个参数表示要判断的类型,第二个参数表示需要将其转换的类型。可以方便进行类型转换的判断,避免了一些类型错误的发生。

#include <type_traits>
#include <iostream>
using namespace std;

template<typename T>
void processInts(T num)
{
    if(is_convertible<T, int>::value)
    {
        int intValue = static_cast<int>(num);
        cout<<"Integer value is "<<intValue<<endl;
    }
    else
    {
        cout<<"Not an integer"<<endl;
    }
}

int main()
{
    processInts(5);
    processInts(3.14);
    return 0;
}
1.09 std::is_copy_assignable

检查一个类型是否支持拷贝赋值操作。

#include <iostream>
#include <type_traits>

class A{
public:
    A() = default;
    ~A() = default;
    A(const A&) = default;
    A& operator=(const A&) = delete;   // 禁止拷贝赋值
};

int main() {
    std::cout << std::boolalpha;    // 输出bool类型值为true/false时,打印为"true"/"false",而不是1/0

    std::cout << std::is_copy_assignable<int>::value << std::endl;     // true
    std::cout << std::is_copy_assignable<A>::value << std::endl;       // false

    return 0;
}
1.10 std :: is_copy_constructible

检查该对象类型是否可以复制

#include <iostream>
#include <type_traits>

class A {
public:
    A() = default;
    A(const A&) = delete;
};

int main() {
    std::cout << std::boolalpha;
    std::cout << "A is copy constructible? " << std::is_copy_constructible<A>::value << '\n'; // false
    std::cout << "int is copy constructible? " << std::is_copy_constructible<int>::value << '\n'; // true
    std::cout << "std::string is copy constructible? " << std::is_copy_constructible<std::string>::value << '\n'; // true
}
1.11 std::is_default_constructible

用于判断一个类型是否有默认构造函数

#include <iostream>
#include <type_traits>

class A {
public:
    A(int a): m_a(a) { }
private:
    int m_a;
};

class B {
public:
    B() = default;
private:
    double m_b;
};

int main() {
    std::cout << std::boolalpha;
    std::cout << "Class A is default constructible: " << std::is_default_constructible<A>::value << '\n';
    std::cout << "Class B is default constructible: " << std::is_default_constructible<B>::value << '\n';
    std::cout << "Basic type int is default constructible: " << std::is_default_constructible<int>::value << '\n';
    std::cout << "Array of type int is default constructible: " << std::is_default_constructible<int[]>::value << '\n';
    return 0;
}
1.12 std::is_destructible

检查一个类是否有可析构的类型。这有助于我们在编译时发现潜在的问题。

#include <iostream>
#include <fstream>
#include <type_traits>

class MyClass {
public:
  MyClass(int size) : arr(new int[size]), file("example.txt") {}
  ~MyClass() { delete [] arr; }

private:
  int* arr;
  std::ofstream file;
};

int main() {
  std::cout << std::boolalpha;
  std::cout << "MyClass is destructible: " << std::is_destructible<MyClass>::value << '\n';
  std::cout << "int[] is destructible: " << std::is_destructible<int[]>::value << '\n';
  std::is_destructible<std::ofstream>::value << '\n';
}
#include <iostream>
#include <type_traits>

template<typename T, typename std::enable_if<std::is_destructible<T>::value, int>::type = 0>
void func(T t) {
  std::cout << "T is destructible" << '\n';
}

class MyClass {
public:
  ~MyClass() {}

private:
  std::ofstream file;
};

int main() {
  MyClass myobj;
  func(int{});
  func(myobj);
  func(int[]{});
  func(std::ofstream{});
}
1.13 std::is_enum

检查一个类型是否是枚举类型。

#include <type_traits>
#include <iostream>
enum class Color { Red, Blue, Green };
int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_enum<Color>::value << '\n'; // true
    std::cout << std::is_enum<int>::value << '\n'; // false
}
1.14 std::is_function

检查给定类型是否为函数。

#include <iostream>
#include <type_traits>

void foo() {}

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_function<decltype(foo)>::value << std::endl; // true
    std::cout << std::is_function<int>::value << std::endl; // false
    std::cout << std::is_function<int(int)>::value << std::endl; // false
    std::cout << std::is_function<int(*)(int, int)>::value << std::endl; // false
    std::cout << std::is_function<decltype([](int x) { return x * x; })>::value << std::endl; // false
    std::cout << std::is_function<decltype([](int x) -> int { return x * x; })>::value << std::endl; // false
    return 0;
}
1.15 std::is_heap

判断一个给定区间是否是堆。

#include <algorithm>
#include <iostream>
#include <vector>

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

    if (std::is_heap(v.begin(), v.end())) {
        std::cout << "v is a heap" << std::endl;
    } else {
        std::cout << "v is not a heap" << std::endl; // √
    }
    return 0;
}
1.16 std::is_integral

判断一个类型是为int、bool、char、short、long等等整型类型的一种.

#include <iostream>
#include <type_traits>
int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_integral<int>::value << std::endl;   // 输出true
    std::cout << std::is_integral<float>::value << std::endl; // 输出false
    std::cout << std::is_integral<bool>::value << std::endl;  // 输出true
    std::cout << std::is_integral<char>::value << std::endl;  // 输出true
    std::cout << std::is_integral<std::string>::value << std::endl; // 输出false
    return 0;
}
1.17 std::is_literal_type

有一种数据类型被称作字面类型,也就是能够用字面量进行初始化的类型。如int、float、double、char、bool等等都是字面类型。

#include <type_traits>
#include <string>
#include <iostream>

struct MyLiteralType
{
   int i;
   float f;
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_literal_type<int>::value << '\n';           // true
    std::cout << std::is_literal_type<MyLiteralType>::value << '\n'; // true
    std::cout << std::is_literal_type<std::string>::value << '\n';   // false
    return 0;
}
1.18 std::is_member_function_pointer

判断一个类成员函数指针是否属于成员函数指针类型。

#include <iostream>
#include <type_traits>

class Example {
public:
    void do_something() {}
};

int main() {
    typedef void (Example::*member_fn_ptr)();
    member_fn_ptr fn = &Example::do_something;

    bool is_mf_ptr = std::is_member_function_pointer<decltype(fn)>::value;
    if (is_mf_ptr) {
        std::cout << "fn is a member function pointer" << std::endl; // √
    } else {
        std::cout << "fn is not a member function pointer" << std::endl;
    }
    return 0;
}
1.19 std::is_member_object_pointer

用于标识是否为成员对象指针的类型特征(trait)的机制。
是成员对象指针的形参或对象返回true,否则返回false。可以使用这种特征将函数模板专门用于成员对象指针。

#include <iostream>
#include <type_traits>

class Test1 {
public:
    int x;
};

class Test2 {
public:
    static int y;
};

class Test3 {
public:
    void show();
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_member_object_pointer<decltype(&Test1::x)>::value << '\n'; // true
    std::cout << std::is_member_object_pointer<decltype(&Test2::y)>::value << '\n';  // false
    std::cout << std::is_member_object_pointer<decltype(&Test3::show)>::value << '\n'; // false
    return 0;
}
1.20 std::is_member_pointer

判断一个类型是否是成员指针类型

class MyClass {
public:
    int myInt;
    void myFunc(int x) { ... }
};

int MyClass::* pMyInt = &MyClass::myInt;  // 成员变量指针
void (MyClass::* pMyFunc)(int) = &MyClass::myFunc;  // 成员函数指针
#include <type_traits>

class MyClass {
public:
    int myInt;
    void myFunc(int x) { ... }
};

int main() {
    // 检查成员指针类型
    bool isPMyInt = std::is_member_pointer_v<decltype(&MyClass::myInt)>;
    bool isPMyFunc = std::is_member_pointer_v<decltype(&MyClass::myFunc)>;

    // 输出检查结果
    std::cout << std::boolalpha << isPMyInt << std::endl;  // true
    std::cout << std::boolalpha << isPMyFunc << std::endl;  // true
}
1.21 std::is_move_assignable

在编译期根据模板参数T的类型推导出一个std::integral_constant类型的值,该值为true表示类型T支持移动赋值运算符,否则为false。

static_assert(std::is_move_assignable<MyType>::value, "MyType must be move assignable");
1.22 std::is_move_constructible

动态地判断一个类型是否支持移动构造函数。

void test_is_move_constructible()
{
    // 定义一个支持移动构造函数的类型
    struct Movable
    {
        Movable() {}
        Movable(const Movable&) {}
        Movable(Movable&&) {}
    };

    // 定义一个不支持移动构造函数的类型
    struct NotMovable
    {
        NotMovable() {}
        NotMovable(const NotMovable&) {}
        NotMovable(NotMovable&&) = delete;
    };

    // 判断类型是否支持移动构造函数
    bool movable_is_mc = is_move_constructible<Movable>::value;
    bool not_movable_is_mc = is_move_constructible<NotMovable>::value;

    cout << "Movable is_move_constructible: " << movable_is_mc << endl;
    cout << "NotMovable is_move_constructible: " << not_movable_is_mc << endl;

    // 构造两个Vector
    Vector<Movable> movable_vector;
    Vector<NotMovable> not_movable_vector;

    Vector<Movable> movable_vector1(move(movable_vector));
    Vector<NotMovable> not_movable_vector1(move(not_movable_vector));// error
}
1.23 std::is_nothrow_assignable

判断一个类型是否可以被安全地赋值,也就是在被赋值后不会抛出异常。

template <typename T>
class Array {
    public:
        Array() { }
        Array(const Array&) { }
        ~Array() { }
        void operator=(const Array&) noexcept { }
};

int main() {
    std::cout << std::boolalpha;
    std::cout << "Array<int> is nothrow assignable? "
              << std::is_nothrow_assignable<Array<int>>::value << '\n';

    std::cout << "Array<Point> is nothrow assignable? "
              << std::is_nothrow_assignable<Array<Point>>::value << '\n';
}
//有const限定符的类,并需要使用std::is_nothrow_assignable来判断它是否可以被安全地赋值。

class MyClass {
    public:
        MyClass() { }
        MyClass(const MyClass&) { }
        ~MyClass() { }
        void operator=(const MyClass&) const noexcept { }
};

int main() {
    std::cout << std::boolalpha;
    std::cout << "MyClass is nothrow assignable? "
              << std::is_nothrow_assignable<const MyClass&>::value << '\n';
}
1.24 std::is_nothrow_constructible是

检查一个类型的对象是否可以在不抛出异常的情况下构造。

#include <iostream>
#include <type_traits>

class MyClass1
{
public:
    MyClass1() throw() {} // no-throw constructor
};

class MyClass2
{
public:
    MyClass2(int n) {}
};

int main()
{
    std::cout << "MyClass1 is nothrow constructible: " << std::is_nothrow_constructible<MyClass1>::value << std::endl;
    std::cout << "MyClass2 is nothrow constructible: " << std::is_nothrow_constructible<MyClass2>::value << std::endl;
    return 0;
}

// 如果你想要检查一个类型的其他构造函数是否no-throw,需要使std::is_nothrow_constructible结合std::declval。
1.25 std::is_nothrow_copy_assignable 、std::is_nothrow_move_assignable

以在编译时检查是否有平凡的复制分配操作符,取决于模板参数T是否符合平凡的复制分配操作符;
检查一个类是否可以被无异常移动。

#include <type_traits>
#include <iostream>

class Person {
public:
    Person() = default;
    Person(const Person& p) = default;
    Person& operator=(const Person& rhs) noexcept {
        std::cout << "Copy assignment operator called\n";
        return *this;
    }
};

int main() {
    std::cout << std::boolalpha;
    std::cout << "Is Person nothrow copy-assignable? "
              << std::is_nothrow_copy_assignable<Person>::value << '\n'; // true
    return 0;
}
1.26 std::is_partitioned

判断一个序列是否被划分为了两个部分,其中一部分满足指定条件,另一部分则不满足。

//第一个参数是迭代器,指向要判断的序列的第一个元素;第二个参数是迭代器,指向要判断的序列的末尾元素的下一个位置;第三个参数是一个可调用对象,用来判断序列中的每个元素是否符合某个条件。

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> nums{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    bool is_odd_even_partitioned = std::is_partitioned(nums.begin(), nums.end(), [](int num){
        return num % 2 == 1;
    });

    std::cout << std::boolalpha;
    std::cout << "Is the sequence partitioned into odd & even?: " << is_odd_even_partitioned << std::endl; // true
    return 0;
}
1.27 std::is_permutation

判断两个序列(Sequence)是否互为置换(Permutation)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
    vector<int> v1 = {1, 2, 3, 4, 5};
    vector<int> v2 = {4, 3, 5, 2, 1};
    if (std::is_permutation(v1.begin(), v1.end(), v2.begin())){
        cout << "v1 and v2 are permutations of each other." << endl; //√
    }else{
        cout << "v1 and v2 are not permutations of each other." << endl;
    }
    return 0;
}
1.28 std::is_same

判断两个类型是否完全相同

#include <iostream>
#include <type_traits>

struct A {
    using type = int;
};

struct B {
    using type = long;
};

int main() {
    std::cout << std::boolalpha;  // 设置输出bool类型的值为true和false
    std::cout << std::is_same<A::type, B::type>::value << std::endl;  // false
    std::cout << std::is_same<A::type, int>::value << std::endl;  // true
    return 0;
}
1.29 std::is_sorted

检查一个序列是否已经排序

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> v {1, 2, 3, 4, 5};
    bool sorted = std::is_sorted(v.begin(), v.end());
    std::cout << std::boolalpha << sorted << '\n';
}
#include <iostream>
#include <algorithm>
#include <vector>

struct Person
{
    std::string name;
    int age;
};

bool compare_age(const Person& p1, const Person& p2)
{
   return p1.age < p2.age;
}

int main()
{
    std::vector<Person> people {
       { "Alice", 25 },
       { "Bob", 40 },
       { "Charlie", 32 }
    };
    bool sorted = std::is_sorted(people.begin(), people.end(), compare_age);
    std::cout << std::boolalpha << sorted << '\n';
}
1.30 std::is_sorted_until

用来找到一个序列中的第一个未排序的元素的。
first和last分别表示容器中第一个元素和最后一个元素的迭代器,comp是一个用于定义比较关系的二元谓词,如果没有给出比较函数,则默认使用operator<进行比较。

#include <iostream>
#include <algorithm>
#include <vector>

bool myFunction(int i, int j) { return (i < j); }

int main() {
  std::vector<int> arr{ 1, 2, 4, 3, 5, 6 };

  auto check_point = std::is_sorted_until(arr.begin(), arr.end());
  bool is_sorted = (check_point == arr.end());

  if (is_sorted) {
    std::cout << "The array is sorted" << std::endl;
  } else {
    std::cout << "The array is not sorted, first unsorted element: " << *check_point << std::endl;
  }

  auto check_point2 = std::is_sorted_until(arr.begin(), arr.end(), myFunction);
  bool is_sorted2 = (check_point2 == arr.end());

  if (is_sorted2) {
    std::cout << "The array is sorted" << std::endl;
  } else {
    std::cout << "The array is not sorted, first unsorted element: " << *check_point2 << std::endl;
  }
  return 0;
}
1.31 std::is_trivially_assignable,

T表示要判断的类型,U表示如果T可以进行赋值操作,那么赋值操作的参数类型。如果T无法赋值,那么U没有意义。

#include <iostream>
#include <type_traits>

struct S {
    int a;
    double b;
};

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_trivially_assignable<S,S>::value << std::endl;
    std::cout << std::is_trivially_assignable<S const,S>::value << std::endl;
    std::cout << std::is_trivially_assignable<S,S const>::value << std::endl;
    std::cout << std::is_trivially_assignable<S const,S const>::value << std::endl;
    return 0;
}
1.32 std::is_trivially_constructible

用于评估一个类型T是否可以被默认构造

#include <iostream>
#include <type_traits>
struct T {
    T() : x(0), y(0) {}  // default constructor
    int x;
    int y;
};
int main() {
    std::cout << std::is_trivially_constructible<T>::value << std::endl;  // false
    return 0;
}
#include <iostream>
#include <type_traits>
struct T {
    int x;
    int y;
};
int main() {
    std::cout << std::is_trivially_constructible<T>::value << std::endl;  // 1
    return 0;
}
1.32 std::is_trivially_copyable

检测一个类型是否是“平凡可复制的(trivially copyable)”。平凡可复制类型是一种可以被复制内存的类型,其复制操作等同于memcpy操作。
C++11标准中,对平凡可复制类型的定义如下:
类型是标量类型(比如整数类型、浮点类型、指针类型、枚举类型)或者数组类型且其元素类型也是平凡可复制的类型
类型有一个平凡的拷贝构造函数
类型有一个平凡的拷贝赋值操作符

#include <iostream>
#include <type_traits>

struct Example {
    int a;
    float b;
};
int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_trivially_copyable<Example>::value << std::endl; // 输出 true
    return 0;
}
#include <iostream>
#include <type_traits>

struct Example {
    int a;
    float b;
    Example() {} // 这里定义了一个空的构造函数
};

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_trivially_copyable<Example>::value << std::endl; // 输出 false
    return 0;
}
1.33 std::is_trivially_copy_assignable

判定一个类型是否具有平凡复制赋值(trivially copy assignable)的特征类。

#include <type_traits>
#include <iostream>

class MyClass {
public:
    int a;
    std::string s;
};

class MyClass2 {
public:
    int a;
    char str[10];
};

int main()
{
    bool is_good = std::is_trivially_copy_assignable<MyClass>::value;
    std::cout << std::boolalpha << is_good << '\n'; // false

    bool is_good2 = std::is_trivially_copy_assignable<MyClass2>::value;
    std::cout << std::boolalpha << is_good2 << '\n'; // true
    return 0;
}
1.34 std::is_nothrow_default_constructible

用于确定给定类型是否具有默认构造函数并且该构造函数是否拥有noexcept保证。

#include <type_traits>

class A {};
class B { public: B() noexcept {} };

int main() {
  static_assert(std::is_nothrow_default_constructible<A>::value, "error: A is not nothrow default constructible"); // error
  static_assert(std::is_nothrow_default_constructible<B>::value, "error: B is not nothrow default constructible");
}
1.35 std::apply

它允许以元组的方式将参数传递给一个可调用对象(函数、函数指针、成员函数指针、函数对象等)

#include <iostream>
#include <tuple>
#include <utility>

int add(int first, int second) { return first + second; }
auto add_lambda = [](auto first, auto second) { return first + second; };

int main()
{
    // OK
    std::cout << std::apply(add, std::pair(1, 2)) << '\n';
    // OK
    std::cout << std::apply(add_lambda, std::pair(2.0f, 3.0f)) << '\n'; 
}
posted @ 2019-06-24 22:53  osbreak  阅读(740)  评论(0编辑  收藏  举报