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';
}