模板元函数应用:输出字符串。

看下面三个字符串,s1,s2,s3 :

    string s1 = "逆天邪神";wstring s2 = _t("焚星妖莲");_string s3 = "焚绝尘";

在控制台输出字符串,可能的一个方案是:

void print_test(const wstring& s) {std::wcout << s << _t("\n");
}void print_test(const string& s) {std::cout << s << "\n";
}void print_test(const _string& s) {
#ifdef _UNICODEstd::wcout << s << _t("\n");
#elsestd::cout << s << "\n";
#endif
}int main() {    string s1 = "逆天邪神";wstring s2 = _t("焚星妖莲");_string s3 = "焚绝尘";print_test(s1);print_test(s2);print_test(s3);return 0;
}

输出:

但是再增加一个类型呢?

如果你想正确运行,除非再增加一个重载函数

或者

或者在类_StrA中增加一个类型转换函数

inline  operator std:string () const { return std::string(_pData); }

以上方案肯定不现实,现在你可能会改用模板函数来代替以下重载函数:

void print_test(const wstring& s) {  std::wcout << s << _t("\n");}void print_test(const string& s) {    std::cout << s << "\n";}void print_test(const _string& s) {
#ifdef _UNICODEstd::wcout << s << _t("\n");
#elsestd::cout << s << "\n";
#endif
}void print_test(const _Str<char>& s) {    std::cout << s << "\n";}

template<class T>
void test(const T& s) {}

但问题来了,如何判断T是 ANSI 还是UNICODE呢,这样子

行不行?

显然不行:

下面给出解决方案:


template<class StringClass,class ElemType = char>
void _cout_s(const StringClass& s, ElemType c) {cout << s << "\n";
}template<class StringClass, class ElemType = wchar_t>
void _cout_s(const StringClass& s, wchar_t w) {wcout << s << _t("\n");
}template<class StringClass>
void _cout_s(const StringClass& s) {_cout_s(s, *s.begin());
}int main() {    string s1 = "逆天邪神";wstring s2 = _t("焚星妖莲");_string s3 = "焚绝尘";_Str<char> s4 = "九阳天怒";_cout_s(s1);_cout_s(s2);_cout_s(s3);_cout_s(s4);return 0;
}

程序正确输出给果:

这里的关键点是:编译器会自动匹配最佳模板函数:

当 *s.begin() 的类型是 char 时,匹配的是:

当 *s.begin()的类型是 wchar_t时,匹配的是:

如果有兴趣可以看看这篇文章:

SFINAE :关于is_class,is_base_of,C++编译器的魔法器,如何实现,is_class,is_base_of。-CSDN博客

下面看应用:

打印计数

/// <summary>
/// 对列表的每一项计数,返回关联容器(项,出现次数)
/// </summary>
/// <typeparam name="CollectionClass"></typeparam>
/// <typeparam name="value_type"></typeparam>
/// <param name="col"></param>
/// <returns></returns>
/// 创建时间: 2024-11-16     最后一修改时间:2024-11-16  
template<typename value_type, typename CollectionClass = std::list<value_type>>
std::map<value_type,size_t> count(const CollectionClass& col) {std::map<value_type, size_t> m;for (const value_type& v : col) {++m[v];}		return m;
}/// <summary>
/// 打印计数
/// 用法:
/// 	std::list<std::wstring> ss1 = { _t("if"),_t("for"),_t("for"),_t("int")};
/// 	std::list<std::string> ss2 = { "if","for" ,"for","int" };
/// 	alg.word_count_print<wstring>(ss1);
/// 	alg.word_count_print<string>(ss2);
/// 
/// </summary>
/// <typeparam name="list_type"></typeparam>
/// <typeparam name="value_type"></typeparam>
/// <param name="sl"></param>
/// 创建时间: 2024-11-16     最后一修改时间:2024-11-16  
template<typename value_type,typename list_type = std::list<value_type>>
void word_count_print(const list_type& sl) {if (sl.size() == 0) return;		auto m = count<value_type>(sl);for (const auto& p : m)  //对map中的每个无素				{mf::_cout_s(p.first);std::cout <<"\t\t"<< p.second << std::endl;//打印结果}
}

例子1:

例子2:

int main() {      _StringList C_Keyword = {_t("alignas"),_t("alignof"),_t("asm"),_t("auto"),_t("bool"),_t("break"),_t("case"),_t("catch"),_t("char"),_t("char16_t"),_t("char32_t"),_t("class"),_t("const"),_t("constexpr"),_t("const_cast"),_t("continue"),_t("decltype"),_t("default"),_t("delete"),_t("do"),_t("double"),_t("dynamic_cast"),_t("each"),_t("else"),_t("enum"),_t("explicit"),_t("export"),_t("extern"),_t("false"),_t("float"),_t("for"),_t("friend"),_t("gcnew"),_t("goto"),_t("if"),_t("in"),_t("inline"),_t("int"),_t("long"),_t("mutable"),_t("namespace"),_t("new"),_t("noexcept"),_t("nullptr"),_t("operator"),_t("private"),_t("protected"),_t("public"),_t("register"),_t("reinterpret_cast"),_t("return"),_t("short"),_t("signed"),_t("size_t"),_t("sizeof"),_t("static"),_t("static_assert"),_t("static_cast"),_t("struct"),_t("switch"),_t("template"),_t("this"),_t("thread_local"),_t("throw"),_t("true"),_t("try"),_t("type"),_t("typedef"),_t("typeid"),_t("typename"),_t("union"),_t("unsigned"),_t("using"),_t("virtual"),_t("void"),_t("volatile"),_t("wchar_t"),_t("while"),};alg.word_count_print<_string>(C_Keyword);return 0;
}

输出:

下面是一些模板元函数的一些代码:

/*************************************************************************
文件名						: _Metafunction.h功能							: 元函数作者							: 李锋手机							: 13828778863Email						: ruizhilf@139.com创建时间						: 2024年01月20日上一次修改时间				: ---------------------------------2024年01月20日最后一次修改时间				: ------------------------  -------2024年11月17日C++惯用法:metafunction(元函数)Metafunction: compile-time analogs of runtime functions
(元函数:编译期的函数)与运行期使用函数封装算法相对应,在C++编译期同样存在着封装算法进行编译期计算的需要。元函数(metafunction)便是实现这一需求的主要手段。元函数这一概念最早是由Boost.MPL类库提出并定义的。作为在编译期进行计算的函数,元函数具有以下不同于运行期函数的特点:输入(即参数)与输出(即返回值)均只包含两种类型:1)类型(名)2)整形常量。可以返回一个或多个值,但不能没有返回值。没有副作用:元函数在计算过程中既不能改变参数的值,也不具备“向控制台输入输出”之类的附加功能。来处:https://blog.csdn.net/suparchor/article/details/115236785*******************************************************************************************/
#pragma once#include "_Macro.h"//_LF_BEGIN_////注意,以后全部使用标准库
using namespace std;//namespace mf //----------------------------------------
{ /*代码1定义了一个用于编译期类型选择的元函数_if,其实现依赖于类模板_if及其特化。元函数_if的输入由3个模板参数构成:布尔类型B,类型名L,类型名R。元函数_if的输出也就是需要返回的类型由typedef语句来定义,用于返回的类型名为type。此处用于返回的类型名取名为type是为了遵循Boost.MPL类库的惯例。若B的值为true,则元函数_if返回类型名L。(此分支由模板特化来定义)若B的值为false,则元函数_if返回类型名R。(此分支由主模板来定义)此处用struct关键字而不是class关键字来定义类模板的理由是:元函数_if的返回类型必须能被外界所访问,即type的访问权限必须是public。*//****** 代码1 ******/template <bool B, typename L, typename R>struct _if{typedef R type;};template <typename L, typename R>struct _if<true, L, R>{typedef L type;};//使用例子:/*//使用的是_if<bool B, typename L, typename R>::type => int_if<false, int, long>::type i; // is equivalent to long i;//使用的是:_if<true,L,R>::type => long_if<true, int, long>::type i;*//*模板元编程的基础是模板和模板特化。模板是一种通用的代码模式,可以根据参数类型进行实例化。模板特化是指为某些特定的参数类型提供专门的实现。例如,我们可以编写一个模板类来表示二叉树节点,然后根据实际情况特化该模板类以提供不同的行为。模板元编程的核心是模板参数的计算。在模板元编程中,模板参数可以是常量表达式,并且可以在编译时进行计算。这意味着我们可以使用模板参数来进行编译时计算,并且可以根据计算结果来生成代码。例如,我们可以编写一个模板函数来计算斐波那契数列,如下所示:抄自:知乎 https://zhuanlan.zhihu.com/p/625244425*/	 template <int N>struct Fibonacci{static constexpr int value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value;};template <>struct Fibonacci<0>{static constexpr int value = 0;};template <>struct Fibonacci<1>{static constexpr int value = 1;};/** 在C++中,我们可以使用sizeof运算符来计算类型的大小。但是,sizeof运算符只能在运行时进行计算。如果我们想在编译时计算类型大小,该怎么办呢?这时候,模板元编程就可以派上用场了。我们可以编写一个模板函数来计算类型大小,如下所示:抄自:知乎 https://zhuanlan.zhihu.com/p/625244425*/template <typename T>struct Sizeof{ static constexpr size_t value = sizeof(T);};/*在C++中,我们可以使用可变参数模板来实现函数的可变参数列表。但是,如果我们想在编译时获取函数的参数个数,该怎么办呢?这时候,模板元编程也可以派上用场。我们可以编写一个模板函数来计算函数的参数个数,如下所示:抄自:知乎 https://zhuanlan.zhihu.com/p/625244425*/template <typename ReturnType, typename... Args>struct FunctionTraits { static constexpr size_t arity = sizeof...(Args); }; template <typename ReturnType, typename... Args>struct FunctionTraits<ReturnType(*)(Args...)> : public FunctionTraits<ReturnType, Args...> {};/*在递归算法中,我们经常需要计算递归深度。如果递归深度很大,那么在运行时进行计算可能会导致栈溢出。这时候,模板元编程就可以派上用场。我们可以编写一个模板函数来计算递归深度,如下所示:抄自:知乎 https://zhuanlan.zhihu.com/p/625244425*/template <int N>struct RecursionDepth{ static constexpr int value = RecursionDepth<N - 1>::value + 1;}; template <>struct RecursionDepth<0> { static constexpr int value = 0; };/*可变模板是C++11中引入的新特性,可以实现可变参数的模板。它的基本语法如下:template <typename... Args>void func(Args... args){ // do something with args...}在这个例子中,Args是一个参数包,它可以包含任意数量的类型。在函数体中,我们可以使用args...来展开参数包,对每个参数执行相同的操作。例如,我们可以使用可变模板来实现一个可变长参数的printf函数:int main(){my_printf("Hello, %s! The answer is %d.\n", "world", 42);return 0;}抄自:知乎 https://zhuanlan.zhihu.com/p/625244425*/inline void my_printf(const char* s){ std::cout << s;} template <typename T, typename... Args>void my_printf(const char* s, T value, Args... args) { while (*s) { if (*s == '%' && *(s + 1) != '%') { std::cout << value; my_printf(s + 1, args...); return; } std::cout << *s++; } throw std::logic_error("extra arguments provided to my_printf");} /*SFINAE技术SFINAE(Substitution Failure Is Not An Error)是一种在C++中使用模板元编程来处理编译时错误的技术。其基本思想是,如果一个模板无法匹配某个类型,那么编译器不会报错,而是选择忽略这个模板,继续寻找其他可用的模板。这种技术可以用来处理函数重载、类型转换和检查类型是否具有某个成员函数等问题。下面是一个例子,展示了如何使用SFINAE技术来处理函数重载问题:抄自:知乎 https://zhuanlan.zhihu.com/p/625244425*/template <typename T>void foo(T t, typename T::type* = nullptr){ // do something if T has a member type} template <typename T>void foo(T t, typename std::enable_if<!std::is_class<T>::value>::type* = nullptr){// do something if T is not a class}#if _c_version_ > _c_14_template <typename... Ts>constexpr auto Sum(Ts... args){return (0 + ... + args);}
#else/// <summary>/// 求和,返回值取决于第1个参数类型/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>/// 创建时间:2024-01-24   抄自:https://dandelioncloud.cn/article/details/1578019250923335681template <typename T>constexpr auto Sum() {return T();  //原文是:T(0)}template <typename T, typename... Ts>constexpr auto Sum(T arg, Ts... args) {return arg + Sum<T>(args...);}#endif/*这段代码的逻辑行为是,如果B为true,则函烽返回T,否则返回F。典型的使用方式为:	mf::conditional<true, int, _string>::type var1 = 10;mf::conditional<false, int, _string>::type var2 = "test";*/template<bool B, typename T, typename F>struct conditional {using type = T;};template<typename T, typename F>struct conditional<false, T, F> {using type = F;};/*下面这段代码:*			:这是一个指针声明。它表示我们想要声明一个指向std::enable_if_t<!Check>类型的指针。= nullptr	:这是给这个指针一个默认初始化值nullptr。test_fun1<true>   匹配的是  ① , est_fun1<false>匹配的是 ②*///test_fun1<true> ①  template<bool Check, std::enable_if_t<Check>* = nullptr>auto test_fun1() {return (int)0;  // ②   test_fun1<true> }//test_fun1<false> ②template<bool Check, std::enable_if_t<!Check>* = nullptr>auto test_fun1() {		 return (double)0.0;  // ②  test_fun1<false> }/// <summary>/// 求整数所对应的二进制表示中1的个数/// </summary>/// <typeparam name="Input"></typeparam>/// 创建时间:2024-03-24   抄自:《动手打造深度学习框架》 21页template<size_t Input>  constexpr size_t OnesCount = (Input % 2) + OnesCount< (Input / 2) >;  template<> constexpr size_t OnesCount<0> = 0;  /*--------------------------------  * //-------------------------------编译时求和template<size_t...Inputs>constexpr size_t Accumulate = 0;  //用于终止循环的分支template<size_t CurInput, size_t...Inputs>constexpr size_t Accumulate<CurInput, Inputs...> = CurInput + Accumulate<Inputs...>;//-------------------------------运行时求和template<size_t...Inputs>size_t Accumulate = 0;template<size_t CurInput, size_t...Inputs>size_t Accumulate<CurInput, Inputs...> = CurInput + Accumulate<Inputs...>;------------------------------*/	 #if _c_version_ > _c_14_//C++17  mf::Accumulate<1, 3, 4, 7>()  //是函数,加括号//C++14  mf::Accumulate<1, 3, 4, 7> /// <summary>/// 元函数,求和 例子:mf::Accumulate<1, 3, 4, 7>();/// </summary>/// <typeparam name="...values"></typeparam>/// <returns></returns>/// 创建时间:2024-03-24   抄自:《动手打造深度学习框架》 23页template<size_t... values>constexpr size_t Accumulate(){return (0 + ... + values);}
#else/// <summary>/// 元函数,求和 例子:mf::Accumulate<1, 3, 4, 7>;/// </summary>/// <typeparam name="...Inputs"></typeparam>/// 创建时间:2024-03-24   抄自:《动手打造深度学习框架》 22页template<size_t...Inputs>  constexpr size_t Accumulate = 0;  //用于终止循环的分支template<size_t CurInput, size_t...Inputs>constexpr size_t Accumulate<CurInput, Inputs...> = CurInput + Accumulate<Inputs...>;
#endif#if _c_version_ > _c_14_	/// <summary>/// 给定一个数值序列,将序列中的每个元素加1,构造新的序列/// </summary>/// <typeparam name="...I"></typeparam>/// 创建时间:2024-03-24   抄自:《动手打造深度学习框架》 24页template<size_t... I>struct Cont;template<size_t... I>using AddOne = Cont<(I + 1)...>; #endif/// <summary>/// 判断一个数是否为奇数/// </summary>/// <typeparam name="N"></typeparam>/// 创建时间:2024-03-24   抄自:《动手打造深度学习框架》 29页template<size_t N>constexpr bool is_odd = ((N % 2) == 1);/// <summary>/// /// </summary>/// <typeparam name="T"></typeparam>/// 创建时间:2024-04-14   最后一修改时间:2024-04-14  已测试template<class T>constexpr size_t SizeOfValue = sizeof(T);/// <summary>/// /// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="n"></typeparam>/// 创建时间:2024-04-14   最后一修改时间:2024-04-14  已测试template<class T, const size_t n>constexpr size_t IsSizeValue = (sizeof(T) == n ? true : false);/// <summary>/// 求整数的最大值/// T(-1) > 0 ,如果成立,表示这T是无符号整数/// 无符号整数的最大值是 T(-1)/// 有符号整数的最大值是 (2^ sizoef(T) * 8 - 1) -1/// 例:8位有符号整数是:2^7 - 1 = 127/// </summary>/// <typeparam name="T"></typeparam>template<class T>constexpr T IntMaxValue = T(-1) > 0 ? T(-1) : (1 << sizeof(T) * 8 - 1) - 1;/// <summary>/// 求整数的最小值/// T(-1) > 0 ,如果成立,表示这T是无符号整数/// 无符号整数的最小值是 0/// 负数的补码 = 机器码除符号位外取反 + 1 = 机器码/// 负数原码:= 机器码除符号位外取反- 1/// 1000000:的机器码 = 11111111 - 1 = -127 - 1 = 128/// 因此:所有有符号整数的最小值 = 它的最小值的相反数再减1/// 计算公式:10000000 = -( 2 ^ 7 - 1)	  - 1 = -128///			 10000001 = -( 2 ^ 7 - 2)	  - 1 = -127///			 ......///			 11111111 = -(2 ^ 7 - 2 ^ 7 ) - 1 = -1/// 八位二进制能表示的负数是 (10000000 ~ 11111111) -1 ~ -128 ///					正数是 (00000000 ~ 01111111) 0  ~ 127  (多了个0)/// 2^8 - 1 = 256个数  其中127个正数,128个负数,加上1个0,总共是 256个数。/// </summary>/// <typeparam name="T"></typeparam>template<class T>constexpr T IntMinValue = T(-1) > 0 ? 0 :  - (1 << sizeof(T) * 8 - 1);/// <summary>/// 判断类型 T 是否class,与 std::is_class 一样。/// 摘抄自:  https://www.cnblogs.com/gx520/p/4614717.html///	SFINAF	这几天神游到一段is_base_of的代码迷惑了很久, 在查资料的过程/// 当中, 发现C++中一种称之为SFINAE的技巧, 全称为"匹配失败并不是一/// 种错误(Substitution Failure Is Not An Error)". 这是一种专门利/// 用编译器匹配失败来达到某种目的的技巧./// </summary>/// <typeparam name="T"></typeparam>/// 创建时间:2024-05-07   最后一修改时间:2024-05-07  已测试template <class T>class is_class{public:/*在is_class类中,定义了一个静态常量value,它的值根据test<T>(0)的大小来确定。如果test<T>(0)返回的是字符类型(即指向类的指针),则value的值为true,表示给定的类型是类;否则,value的值为false,表示给定的类型不是类。		这段代码的作用是提供一个通用的方法来判断一个类型是否为类,可以在编译时进行类型检查和条件编译。如果T是一个类类型,编译器会选择接受指向类的指针的重载版本的test函数,这是因为C++模板的类型推导机制。在C++中,模板是一种特殊的工具,它允许程序员编写可以处理多种数据类型的代码。当使用模板时,编译器会根据提供的模板参数来实例化特定的函数或类。在这个过程中,编译器会尝试匹配最佳的函数重载版本,这一过程称为重载解析(overload resolution)。对于is_class模板类中的两个test函数:template <class U> static char test(int U::*);template <class U> static int test(...);第一个test函数接受一个指向类成员的指针作为参数,这意味着它只能接受一个类类型的参数。第二个test函数是一个可变参数模板函数,可以接受任何类型的参数。当T是一个类类型时,编译器在选择test函数的重载版本时,会优先考虑那些能够接受特定类型参数的函数。因为第一个test函数要求参数必须是一个类的指针类型,而T恰好是一个类类型,所以这个条件得到满足。由于这个重载版本的test函数更具体,更符合T是一个类类型的情况,编译器会优先选择它。总的来说,编译器选择接受指向类的指针的重载版本的test函数,是因为这个重载版本与T作为类类型的条件更加吻合,这是C++模板类型推导和重载解析的结果。*///sizeof(test), 并不会调用函数fun,可以不用函数体template <class U>static char test(int U::*){}//sizeof(test), 并不会调用函数fun,可以不用函数体template <class U>static int test(...){}public:/// <summary>/// test<T>(0),T是类时,两个函数都可以调用,但编译器在选择test函数的重载版本/// 时,会优先考虑那些能够接受特定类型参数的函数。sizoef(char) = 1, 而sizeof(int) = 4,/// 当sizeof(test<T>(0))返回1时,说明调用的是static char test(int U::*),也就是/// 说 T 是一个类类型。/// </summary>/// 创建时间:2024-05-07   最后一修改时间:2024-05-07  已测试static const bool value = sizeof(test<T>(0)) == 1;};template < typename T1, typename T2>struct is_same {static const bool value = false;	};template < typename T>struct is_same<T, T> {static const bool value = true;	};/// <summary>/// 判断类型 Derived 是否Base的派生类,与 std::is_base_of 一样。/// 摘抄自:  https://www.cnblogs.com/gx520/p/4614717.html/// 这个函数只能判断类类型,不能用于基本类型。/// 例如:is_base_of<_Object,_DList<int>>::value,对于is_base_of<double,int>/// 就无能为力了,这就要用到下面的is_base_of了。/// </summary>/// <typeparam name="Base">类型</typeparam>/// <typeparam name="Derived">派生类</typeparam>/// <typeparam name=""></typeparam>/// 创建时间:2024-05-08   最后一修改时间:2024-05-08  已测试template < typename Base, typename Derived, bool = (is_class<Base>::value && is_class<Derived>::value)>class is_base_of {/*test(Conv(),0),有两个可重载函数可选,编译器先检查test(Derived, T),如果Conv能强制类型转换成 Derived(把基类转换成派生类),则匹配这个函数,说明 Derived确实是Base的派生类,否则匹配第二个函数test(Base, int)核心知识:假如 _Font 是 _Object的派生类,下面语句,有一句是不能编译的:_Object o1 = _Font(); //可以,编译通过_Font f = _Object(); //不可以,不能编译通过。就是巧妙利用这点,这实际上是一个SFINAE:匹配失败并不是一种错误(Substitution Failure Is Not An Error)*/template < typename T>static char test(Derived, T) {};  //{}函数体是多余的,可以不用。static int test(Base, int) {};//{}函数体是多余的,可以不用。struct Conv {operator Derived() {}; //{}函数体是多余的,可以不用。operator Base() const {}; //{}函数体是多余的,可以不用。};public:static const bool value = sizeof(test(Conv(), 0)) == 1;};/// <summary>/// 匹配下列式子:/// 	is_base_of<int,_Object>///		is_base_of<_Object,int>///		is_base_of<dobule,int>/// </summary>/// <typeparam name="Base"></typeparam>/// <typeparam name="Derived"></typeparam>/// 创建时间:2024-05-08   最后一修改时间:2024-05-08  已测试template < typename Base, typename Derived>class is_base_of<Base, Derived, false> {public:static const bool value = is_same<Base, Derived>::value;};/// <summary>/// 相同类型的匹配下列式子:/// 	is_base_of<int,int>///		is_base_of<_Object,_Object>/// </summary>/// <typeparam name="Base"></typeparam>/// 创建时间:2024-05-08   最后一修改时间:2024-05-08  已测试template < typename Base>class is_base_of<Base, Base, true> {public:static const bool value = true;};/// <summary>/// /// <summary>/// 参数数量 == 1的函数模板/// 递归终止时调用/// </summary>/// <typeparam name="T"></typeparam>/// <param name="sArray"></param>/// <param name="value"></param>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T>constexpr void get_type_size(std::vector<size_t>& sArray, const T& value){sArray.push_back(sizeof(T));}/// <summary>/// 可变参数模板/// 参数数量 > 1的函数模板/// 递归时调用/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="...Args"></typeparam>/// <param name="sArray"></param>/// <param name="first"></param>/// <param name="...args"></param>/// <returns></returns>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T, typename... Args>constexpr const vector<size_t>& get_type_size(vector<size_t>& sArray, T first, const Args&... args){sArray.push_back(sizeof(T));get_type_size(sArray, args...);return sArray;}/// <summary>/// /// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="...Args"></typeparam>/// <param name="first"></param>/// <param name="...args"></param>/// <returns></returns>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T, typename... Args>constexpr std::vector<size_t>  get_type_size(const T& first, const Args&... args){std::vector<size_t> sArray;get_type_size(sArray, first, args...);return sArray;}/// <summary>/// 功能:返回参数的类型列表/// 参数数量 == 1的函数模板/// 递归终止时调用/// </summary>/// <typeparam name="T"></typeparam>/// <param name="sArray"></param>/// <param name="value"></param>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T>constexpr void get_type_name(vector<string>& sArray, const T& value){sArray.push_back(typeid(T).name());}/// <summary>/// 功能:返回参数的类型列表/// /// 可变参数模板/// 参数数量 > 1的函数模板/// 递归时调用/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="...Args"></typeparam>/// <param name="sArray"></param>/// <param name="first"></param>/// <param name="...args"></param>/// <returns></returns>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T, typename... Args>constexpr const vector<string>& get_type_name(vector<string>& sArray, T first, const Args&... args){sArray.push_back(typeid(T).name());get_type_name(sArray, args...);return sArray;}/// <summary>/// 功能:返回参数的类型列表/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="...Args"></typeparam>/// <param name="first"></param>/// <param name="...args"></param>/// <returns></returns>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T, typename... Args>constexpr vector<string>  get_type_name(const T& first, const Args&... args){vector<string> sArray;return get_type_name(sArray, first, args...);}/// <summary>/// 功能:返回参数的类型列表/// 参数数量 == 1的函数模板/// 递归终止时调用/// </summary>/// <typeparam name="T"></typeparam>/// <param name="sArray"></param>/// <param name="value"></param>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T>constexpr void get_name_size(vector<pair<string,int>>& sArray, const T& value){sArray.push_back(pair<string, int>(typeid(T).name(), sizeof(T)));}/// <summary>/// 功能:返回参数的类型列表/// /// 参数数量 > 1的函数模板/// 递归时调用/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="...Args"></typeparam>/// <param name="sArray"></param>/// <param name="first"></param>/// <param name="...args"></param>/// <returns></returns>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T, typename... Args>constexpr  vector<pair<string, int>>& get_name_size(vector<pair<string, int>>& sArray, T first, const Args&... args){sArray.push_back(pair<string, int> (typeid(T).name(), sizeof(T)));get_name_size(sArray, args...);return sArray;}/// <summary>/// 获取参数的类型和这个类型大小/// 例:///		mf::get_name_size(88,3.14)= {{int,4},{double,8}}/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="...Args"></typeparam>/// <param name="first"></param>/// <param name="...args"></param>/// <returns></returns>/// 创建时间:2024-05-09   最后一修改时间:2024-05-09  已测试template <typename T, typename... Args>constexpr vector<pair<string, int>>  get_name_size(const T& first, const Args&... args){vector<pair<string, int>> sArray;get_name_size(sArray, first, args...);return sArray;}/***********************************以下Size用于计算模板参数的个数,例:using Cont = std::touple<char,double,int>;constexpr size_t Res1 = Size<Cont>;  //Res1 为3constexpr size_t Res2 = Size<Cont&>; //Res2 为3using Cong2 = std::tuple<int, std::string, int, double>;constexpr size_t Res3 = Size(Con2&); //Res3的值为4相当于//Res3的值为4size_t Res3 = mf::Size< std::tuple<int, std::string, int, double>& >;创建时间:2024-03-24   抄自:《动手打造深度学习框架》 37页***********************************/template<typename T>  //1using RemConstRef = std::remove_cv_t<std::remove_reference_t<T>>;template<typename TArray>struct Size_;/// <summary>/// 获取模板参数的个数/// </summary>/// <typeparam name="...T"></typeparam>template<template<typename...> class Cont, typename...T>struct Size_<Cont<T...>>//5{constexpr static size_t value = sizeof...(T);};/// <summary>/// 获取模板参数的个数/// </summary>/// <typeparam name="TArray"></typeparam>template<typename TArray>//10constexpr static size_t Size = Size_<RemConstRef<TArray>>::value;/// <summary>/// 可以构造任意对象的函数(学习可变参数的使用)/// </summary>/// <typeparam name="MyClass">要转换对象的类型</typeparam>/// <typeparam name="...MyClassConstructorParameterTypes">转换对象的构造函数参数类型</typeparam>/// <param name="...MyClassConstructorParameters">转换对象的构造函数参数</param>/// <returns>返回一个对象</returns>/// 创建时间: 2024-09-23      最后一次修改时间:2024-09-23template <class MyClass, typename... MyClassConstructorParameterTypes>MyClass ConverTo(MyClassConstructorParameterTypes&&... MyClassConstructorParameters){return MyClass(std::forward<MyClassConstructorParameterTypes>(MyClassConstructorParameters)...);}/// <summary>/// 控制台输出字符串/// </summary>/// <typeparam name="StringClass"></typeparam>/// <typeparam name="ElemType"></typeparam>/// <param name="s"></param>/// <param name="c"></param>/// 创建时间: 2024-11-17      最后一次修改时间:2024-11-17template<class StringClass, class ElemType = char>void _cout_s(const StringClass& s, ElemType c) {std::cout << s;}/// <summary>/// 控制台输出字符串/// </summary>/// <typeparam name="StringClass"></typeparam>/// <typeparam name="ElemType"></typeparam>/// <param name="s"></param>/// <param name="w"></param>/// 创建时间: 2024-11-17      最后一次修改时间:2024-11-17template<class StringClass, class ElemType = wchar_t>void _cout_s(const StringClass& s, wchar_t w) {std::wcout << s;}/// <summary>/// 控制台输出字符串/// 例子:///		int main() {      ///			string s1 = "逆天邪神";/// 		wstring s2 = _t("焚星妖莲");/// 		_string s3 = "焚绝尘";/// 		_Str<char> s4 = "九阳天怒";/// 		mf::_cout_s(s1);/// 		mf::_cout_s(s2);/// 		mf::_cout_s(s3);/// 		mf::_cout_s(s4);/// 		return 0;///		}/// </summary>/// <typeparam name="StringClass"></typeparam>/// <param name="s"></param>/// 创建时间: 2024-11-17      最后一次修改时间:2024-11-17template<class StringClass>void _cout_s(const StringClass& s) {_cout_s(s, *s.begin());}}//--------------------------------------------mf_LF_END_

下面是一些通用算法,算法库的一些代码:

/*******************************************************************************************
文件名						: _Algorithm.h功能							: 通用算法,算法库作者							: 李锋手机							: 13828778863Email						: ruizhilf@139.com创建时间						: 2024年07月02日最后一次修改时间				:  2024年10月09日注意							:所有base里的头文件都不要包含这个文件注释							:每个算法函数都应该有一个用法例子			*********************************************************************************************/
#pragma once #include "_p.h"
#include "_Metafunction.h"_LF_BEGIN_/// <summary>
/// 用以描述配对
/// </summary>
/// <typeparam name="T"></typeparam>
/// 创建时间: 2024-08-15     最后一修改时间:2024-08-15 
template<class Iterator>
class PairOf : _Object
{public:inline PairOf() = default;/// <summary>/// 指向左边配对数据的指针/// </summary>Iterator itLeft;/// <summary>/// 左路配对数据的长度/// </summary>size_t LeftLength = 0;/// <summary>/// 指向右边配对数据的指针/// </summary>Iterator itRight;/// <summary>/// 右边配对数据的长度/// </summary>size_t RigthLength = 0;/// <summary>/// 用于保存查找的左边配对的位置指针/// </summary>Iterator itLeftPosition;/// <summary>/// 用于保存查找的右边配对的位置指针/// </summary>Iterator itRigthPosition;/// <summary>/// 配对包含的数据的开始指针,此数据包含配对本身/// </summary>/// <returns></returns>const Iterator begin()const { return itLeftPosition; }/// <summary>/// 配对包含的数据的结束位置的后一位指针,此数据包含配对本身/// </summary>/// <returns></returns>const Iterator end()const { return itRigthPosition + RigthLength; }/// <summary>/// 返回配对包含的数据数据,包含配对本身/// </summary>/// <returns></returns>auto PairData() {using T = std::remove_reference_t<decltype(*itLeft)>;int nLength = end() - begin();lassert(itLeftPosition != null && itRigthPosition != null && nLength >= 0,"auto PairData()");_Array<T> aResult(end() - begin() + 1);Iterator it = itLeftPosition;for (size_t n = 0; n < nLength; ++n) { *(aResult.GetDataConst() + n) = *(it + n); }aResult.ResetLength(nLength);aResult.ZeroBufferAll();return aResult;}/// <summary>/// 返回配对包含的数据数据,不包含配对本身/// </summary>/// <returns></returns>inline auto PairOnlyData() {using T = std::remove_reference_t<decltype(*itLeft)>;int nLength = end() - begin() - LeftLength - RigthLength;lassert(itLeftPosition != null && itRigthPosition != null && nLength >= 0,"PairOnlyData()");_Array<T> aResult(end() - begin() + 1);Iterator it = itLeftPosition + LeftLength;for (size_t n = 0; n < nLength; ++n) { *(aResult.GetDataConst() + n) = *(it + n); }aResult.ResetLength(nLength);aResult.ZeroBufferAll();return aResult;}};/// <summary>
/// 不喜欢用 namespace::, 喜欢用 class., 因此用静态类。 
/// lf::sort_selection  改用 alg.sort_selection
/// </summary>
/// 创建时间: 2024-07-25     最后一修改时间:2024-07-25
static class _Algorithm : public _Math
{
public:/*****************************************************************************排序****************************************************************************///排序//参考:https://blog.csdn.net/qq_45615577/article/details/115257685//排序的概念/*排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次 序保持不变,即在原序列中,r[i] = r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排 序算法是稳定的;否则称为不稳定的。内部排序:数据元素全部放在内存中的排序。外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。————————————————版权声明:本文为博主原创文章,遵循 CC 4.0 BY - SA 版权协议,转载请附上原文出处链接和本声明。原文链接:https ://blog.csdn.net/qq_45615577/article/details/115257685*//// <summary>/// 选择排序---直接选择排序/// 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,/// 直到全部待排序的 数据元素排完 。/// 找出序列中的最小关键字,然后将这个元素与序列首端元素交换位置。例如,序列前i个/// 元素已经有序,从第i + 1到第n个元素中选择关键字最小的元素,假设第j个元素为最小/// 元素,则交换第j个元素与第i + 1个元素的位置。依次执行此操作,直到第n - 1个元素/// 也被确定。/// </summary>/// <typeparam name="T">类型</typeparam>/// <param name="pData">开始位置</param>/// <param name="nCount">元素个数</param>/// <param name="so">排序顺序,默认从小到大</param>/// 创建时间: 2024-07-01     最后一修改时间:2024-07-01/// 参考网址:https://blog.csdn.net/qq_45615577/article/details/115257685 template<class T>void Sort_Selection(T* pData, const size_t& nCount, const bool& bMinMax = true){/*7 4 5 9 8 2 11 4 5 9 8 2 72 5 9 8 4 74 9 8 5 75 8 9 77 9 88 9在 [0 , n-1] 中找出最小的放在第一位在 [1 , n-1] 中找出最小的放在第二位...*/if (pData == null || nCount == 0) return;int nSortedCount = 0;  //已排序好的个数if (bMinMax) {while (nSortedCount < nCount) {int  minIndex = nSortedCount;//在[nStart, nCount-1] 中找出最小值for (int n = nSortedCount + 1; n < nCount; ++n) {if (*(pData + n) < *(pData + minIndex)) {minIndex = n;}}if (minIndex != nSortedCount) {T tmp = *(pData + minIndex);*(pData + minIndex) = *(pData + nSortedCount);*(pData + nSortedCount) = tmp;}++nSortedCount;}}else {while (nSortedCount < nCount) {int  maxIndex = nSortedCount;//在[nStart, nCount-1] 中找出最大值for (int n = nSortedCount + 1; n < nCount; ++n) {if (*(pData + n) > *(pData + maxIndex)) {maxIndex = n;}}if (maxIndex != nSortedCount) {T tmp = *(pData + maxIndex);*(pData + maxIndex) = *(pData + nSortedCount);*(pData + nSortedCount) = tmp;}++nSortedCount;}}}/// <summary>/// 返回最小值的位置///		lf::_DList<int> d1 = { 1,3,5,8,2,0 };///		lf::_DList<int> d2 = { 1 };///		lf::_DList<int> d3 = { };///		vector<int> v = { 1,3,5,8,2,0 };//////		_pin(*lf::Min(d1.begin(), d1.end()));  //输出: 0///		_pin(*lf::Min(d2.begin(), d2.end()));  //输出: 1///		_pin(*lf::Min(d3.begin(), d3.end()));  //报错,最少一个元素//////		_pin(*lf::Min(v.begin(), v.end()));  //输出: 0/// /// 	_string s = _t("sdwsffa");///		_pin(*lf::Min(s.begin(), s.end()));  //输出: a/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <returns></returns>/// 创建时间: 2024-07-02     最后一修改时间:2024-07-02template<typename IteratorClass>IteratorClass Min(IteratorClass itBegin, IteratorClass itEnd) {assert(itBegin != itEnd);IteratorClass result = itBegin;itBegin++;while (itBegin != itEnd) {if (*result > *itBegin)result = itBegin;++itBegin;}return result;}/// <summary>///  bool f(t1, t2){  }///  如果函数返回true,则认为 t1 < t2 /// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="fun"></param>/// <returns></returns>/// 创建时间: 2024-10-09     最后一修改时间:2024-10-09template<typename IteratorClass, typename ComparingFunctions>IteratorClass Min(IteratorClass itBegin, IteratorClass itEnd, ComparingFunctions f) {assert(itBegin != itEnd);IteratorClass result = itBegin;itBegin++;while (itBegin != itEnd) {if( f(*itBegin, *result) )  //if *itbegin < *resultresult = itBegin;++itBegin;}return result;}/// <summary>/// 按两种规则查找最小值:/// 先按规则 f 比较,如果f没有比较成功(实际上两个对象按f/// 规则比较是等于),则按对象本身自带的运算符 < 来比较。/// 例子: /// ///		vector<string> v = { "abc6","abc1","abc3","abc2" };//////		auto s1 = alg.Min(v.begin(), v.end(), [](const string& s1, const string& s2)->bool {///			return s1.size() < s2.size();///		});/////////		_pn(*s1);///		auto s2 = alg.min_two_rules(v.begin(), v.end(), [](const string& s1, const string& s2)->bool {///			return s1.size() < s2.size();///		});//////		_pn(*s2);/// /// 输出:///		s1 = abc6///		s2 = "abc1"/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// <returns></returns>/// 创建时间: 2024-10-11     最后一修改时间:2024-10-11template<typename IteratorClass, typename ComparingFunctions>IteratorClass min_two_rules(IteratorClass itBegin, IteratorClass itEnd, ComparingFunctions f) {assert(itBegin != itEnd);IteratorClass result = itBegin;itBegin++;while (itBegin != itEnd) {if (f(*itBegin, *result))  //  小于   if *itbegin < *resultresult = itBegin;else if (f(*result, *itBegin)) {  //大小//什么都不做}else { //即不是大于,又不是小于,再按对象运算符规则if(*itBegin < *result)result = itBegin;}++itBegin;}return result;}/// <summary>/// 创建时间: 2024-07-02     最后一修改时间:2024-07-02/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// <returns></returns>template<typename IteratorClass ,typename ComparingFunctions>IteratorClass Max(IteratorClass itBegin, IteratorClass itEnd, ComparingFunctions f) {assert(itBegin != itEnd);IteratorClass result = itBegin;//itBegin++;while (itBegin != itEnd) {if ( !f(*itBegin, *result))  //if *itbegin < *resultresult = itBegin;++itBegin;}return result;}/// <summary>/// /// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <returns></returns>/// 创建时间: 2024-07-02     最后一修改时间:2024-07-02template<typename IteratorClass>IteratorClass Max(IteratorClass itBegin, IteratorClass itEnd) {assert(itBegin != itEnd);IteratorClass result = itBegin;while (itBegin != itEnd) {if (*result < *itBegin)result = itBegin;++itBegin;}return result;}/// <summary>/// /// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <param name="it1"></param>/// <param name="it2"></param>/// 创建时间: 2024-07-02     最后一修改时间:2024-10-09template<typename IteratorClass>void Swap(IteratorClass it1, IteratorClass it2) {//std::cout << "===================================\n";//_pin(*it1);//_pin(*it2);/*auto tmp = *it1;  //如果*it2是 int& 则,tmp 的类型是int, 并不是int&。*it1 = *it2;*it2 = tmp;*/_Math::swap(*it1, *it2);//_pin(*it1);//_pin(*it2);//std::cout << "===================================\n";}/// <summary>/// 输出itBegin到itEnd之间(不含itEnd)的所有元素,如果分隔符sSeparator为空,/// 则每行输出一个元素,否则每个元素用分隔符分开。/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <param name="itBegin">迭代器开始位置</param>/// <param name="itEnd">迭代器结束位置</param>/// <param name="sSeparator">分隔符</param>/// 创建时间: 2024-08-01     最后一修改时间:2024-08-01template<typename IteratorClass>void Print(IteratorClass itBegin, IteratorClass itEnd, const std::string& sSeparator = "") {//输出beg到end之间(不含end)的所有元素if (itBegin == itEnd) return;if (sSeparator == "") {while (itBegin != itEnd)std::cout << *itBegin++ << std::endl; //输出当前元素并将指针向前移动一个位置std::cout << std::endl;}else {while (itBegin != itEnd - 1)std::cout << *itBegin++ << sSeparator; //输出当前元素并将指针向前移动一个位置std::cout << *itBegin << std::endl;}}/// <summary>/// 输出集合的所有元素,如果分隔符sSeparator为空,/// 则每行输出一个元素,否则每个元素用分隔符分开。/// </summary>/// <typeparam name="CollectionClass"></typeparam>/// <param name="col">集合</param>/// <param name="sSeparator">分隔符</param>/// 创建时间: 2024-08-01     最后一修改时间:2024-08-01template<typename CollectionClass>void Print(const CollectionClass& col, const std::string& sSeparator = "") {print(col.begin(), col.end(), sSeparator);}/// <summary>/// 	lf::_DList<int> d4 = {1,2,3,6,5,4};///		lf::sort_selection(d4.begin(), d4.end(), _SortOrder::s_Minmax);///		_pcn(d4);  //输出:d4={1,2,3,4,5,6}///		lf::sort_selection(d4.begin(), d4.end(), _SortOrder::s_Maxmin);///		_pcn(d4); //输出:d4={6,5,4,3,2,1}/// ///		_string s2 = _t("_DListNodeIterator,abcd,efg");///		_pcn(s2); //s2=_DListNodeIterator,abcd,efg///		lf::sort_selection(s2.begin(), s2.end(), _SortOrder::s_Minmax);///		_pcn(s2); //s2=,,DILN_aabcddeeefgioorrsttt///		lf::sort_selection(s2.begin(), s2.end(), _SortOrder::s_Maxmin);///		_pcn(s2); //s2=tttsrrooigfeeeddcbaa_NLID,,/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="so"></param>/// 创建时间: 2024-07-01     最后一修改时间:2024-10-09(已测试)template<typename IteratorClass>void Sort_Selection(IteratorClass itBegin, IteratorClass itEnd, const bool& bMinMax = true){/*7 4 5 9 8 2 11 4 5 9 8 2 72 5 9 8 4 74 9 8 5 75 8 9 77 9 88 97 2 2 2 2 2 22 7 2 2 2 2 22 7 2 2 2 22 7 2 2 22 7 2 22 7 22 7在 [0 , n-1] 中找出最小的放在第一位在 [1 , n-1] 中找出最小的放在第二位...*/if (bMinMax) {while (itBegin != itEnd) {//在[itBegin + 1, itEnd] 中找出最小值,与itBegin交换		 Swap(itBegin, Min(itBegin, itEnd));itBegin++;}}else {while (itBegin != itEnd) {//在[itBegin + 1, itEnd] 中找出最小值,与itBegin交换Swap(itBegin, Max(itBegin, itEnd));itBegin++;}}}template<typename IteratorClass>void sort(IteratorClass itBegin, IteratorClass itEnd) {Sort_Selection(itBegin, itEnd);}/// <summary>/// std::sort 是从小到大排列的/// 例子代码:///		list<int>  lst1 = { 0,3,2,3,9,9,7,6,5,4,3,1 };///		_list<int> lst2 = { 0,3,2,3,9,9,7,6,5,4,3,1 };  //_DList///		alg.sort(lst1.begin(), lst1.end(), [](const int& i1, const int& i2)->bool {///			return i1 < i2;///		});///		alg.sort(lst2.begin(), lst2.end(), [](const int& i1, const int& i2)->bool {///			return i1 < i2;///		});///		_pn(lst1);///		_pn(lst2);	 /// /// 输出:///		lst1 = {0,1,2,3,3,3,4,5,6,7,9,9}///		lst2 = {0,1,2,3,3,3,4,5,6,7,9,9}/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// 创建时间: 2024-10-09     最后一修改时间:2024-10-09(已测试)template<typename IteratorClass, typename ComparingFunctions>void sort(IteratorClass itBegin, IteratorClass itEnd, ComparingFunctions f) {while (itBegin != itEnd) {Swap(itBegin, Min(itBegin, itEnd,f)); //与std::sort相同,从小到大itBegin++;}}/// <summary>/// /// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// 创建时间: 2024-10-12     最后一修改时间:2024-10-12(已测试)template<typename IteratorClass, typename ComparingFunctions>void sort_two_rules(IteratorClass itBegin, IteratorClass itEnd, ComparingFunctions f) {while (itBegin != itEnd) {Swap(itBegin, min_two_rules(itBegin, itEnd, f)); //与std::sort相同,从小到大itBegin++;}}/// <summary>/// 稳定排序:///		在排序时不改变其序列///		待排序的记录序列中可能存在两个或两个以上关键字相等的记录。///		排序前的序列中Ri领先于Rj(即i<j).若在排序后的序列中Ri仍然领先于Rj,///		则称所用的方法是稳定的。比如int数组 [1, 1, 1, 6, 4] 中 a[0], a[1], a[2]的///		值相等,在排序时不改变其序列,则称所用的方法是稳定的。/// /// stable_sort 是 C++ 标准库中的一个算法,用于对指定范围内的元素进行排序。/// 与 std::sort 不同,stable_sort 保证了相等元素的相对顺序不变,即稳定排序。/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// 创建时间: 2024-10-11     最后一修改时间:2024-10-11(已测试)template<typename IteratorClass, typename ComparingFunctions>void stable_sort(IteratorClass itBegin, IteratorClass itEnd, ComparingFunctions f) {IteratorClass itSwap = itBegin;while (itBegin != itEnd) {auto itMin = Min(itBegin, itEnd, f);//判断下一个元素是否与itBegin相等,如果相等,则itBegin指向下一个元素auto itSwap = itBegin + 1;while (itBegin != itEnd && itBegin != itMin) {				//itBegin和itswap相等if ( f(*itBegin, *itSwap) == false && f(*itSwap, *itBegin) == false){				itSwap++;		}else {//abc1,abc2,abc3 c a  (先保存a元素,然后 [abc1,abc3,abc3,c] 后移一位//a,abc1 abc2,abc3,c auto tValue = *itMin;  //保存数据m.MoveBackIter(itBegin, itMin, 1);*itBegin = tValue;//itBegin = itSwap;	错误,不能用这句,还是在itBegin之前插入	//std::cout << "*itBegin=" << (*itBegin) << "\n";//std::cout << "*itBegin=" << (*(itBegin+1)) << "\n";break;}	 }			itBegin++;}}/*****************************************************************************查找顺序查找二分查找插值查找、斐波那契查找分块查找哈希查找树表查找****************************************************************************/template<typename IteratorType>struct findResult{/// <summary>/// 如果没找到 Index == -1/// </summary>size_t Index;IteratorType Iter;public:inline findResult()	{	Index = _Math::npos;	}inline findResult(const findResult& r)	{Index = r.Index;		Iter = r.Iter;}};/// <summary>/// 顺序查找/// /// 注意:///		如果是向后查找,则返回的索引是以itFirst开始算来,第一个为 0,即itFirst为0。///		如果是向前揸找,则返回的索引是以itLast开始算起,第一个,即itLast为0。///		 /// </summary>/// <typeparam name="IteratorType"></typeparam>/// <typeparam name="DataType"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="tValue"></param>/// <param name="bBackward"></param>/// <returns></returns>/// 创建时间: 2024-07-03     最后一修改时间:2024-07-03template<typename IteratorType, typename DataType>findResult<IteratorType> Find_Sequential(IteratorType itFirst, IteratorType itLast,const DataType& tFindValue, const bool& bBackward = true){findResult<IteratorType> fr;fr.Index = -1;int n = 0;if (bBackward) {  //向后while (true){if (*itFirst == tFindValue) {fr.Index = n;fr.Iter = itFirst;break;}++n;++itFirst;if (itFirst == itLast) break;}}else {while (true){if (*itLast == tFindValue) {fr.Index = n;fr.Iter = itLast;break;}++n;--itLast;if (itFirst == itLast) break;}}return fr;}/// <summary>/// 集合类必须带有 begin() 和 end() 函数/// 例子:///		std::vector<int> v = { 1,2,3,23,435,4646,34 };///		lf::_DList<int> d = { 1,2,3,23,435,4646,34 };///		if (lf::IsExists(d, 23))///		{///		cout << "存在23.\n";///		}///		if (lf::IsExists(v, 55))///		{///			cout << "存在55.\n";///		}/// </summary>/// <typeparam name="value_type"></typeparam>/// <typeparam name="CollectionClass"></typeparam>/// <param name="col"></param>/// <param name="value"></param>/// <returns></returns>/// 创建时间: 2024-07-03     最后一修改时间:2024-07-03template<typename CollectionClass, typename value_type>bool IsExists(const CollectionClass& col, const value_type& value){auto itbegin = col.begin();auto itend = col.end();while (itbegin != itend){if (*itbegin == value)return true;++itbegin;}return false;}/// <summary>/// 二分法查找有序表的通用算法(可查链表,数组,字符串...等等)/// 注意事项:///    (1)你设计的迭代器模板中必须有using value_type = T,且有加减运算功能,///			其本上能与C++标准库std中一样。///		(2)集合必须是有序的。/// 例子:///		vector<int> v;///		find_binary(b.begin(),v.end(),3);  // Inde返回 (-1, *Iterator == ?)/// ///		vector<int> v = {3};///		find_binary(b.begin(),v.end(),3);  // 返回  (Index == 0, *Iterator == 3)///  ///		const char* sz = "abcdefgb";///		auto f3 = lf::find_binary(sz, sz + 8, 'c');  //返回  (Index == 2, *Iterator == c)/// </summary>/// <typeparam name="IteratorType">迭代器类型</typeparam>/// <typeparam name="value_type">值类型</typeparam>/// <param name="itBegin">开始位置</param>/// <param name="itEnd">结束位置</param>/// <param name="vtFindValue">查找值</param>/// <returns>返回索引与指向vtFindValue的迭代器</returns>/// 创建时间: 2024-07-03     最后一修改时间:2024-07-04  (初步测试)template<typename IteratorType,typename value_type>findResult<IteratorType> find_binary(const IteratorType& itBegin, const IteratorType& itEnd, const value_type& vtFindValue){findResult<IteratorType> fr;  auto beg = itBegin;auto end = itEnd;int nCount = end - beg;if (nCount == 0) return fr;if (*(itEnd-1) > *itBegin) {//从小到大排列auto mid = beg + nCount / 2;while (mid != itEnd){if(*mid == vtFindValue){fr.Iter = mid;fr.Index = mid - itBegin;return fr;}if (vtFindValue < *mid)end = mid;elsebeg = mid + 1;  //在mid之后查找mid = beg + (end - beg) / 2;   //新的中间点}	 }else{ //从大到小排列 auto mid = beg + nCount / 2;while (mid != itEnd) {if (*mid == vtFindValue) {fr.Iter = mid;fr.Index = mid - itBegin;return fr;}if (vtFindValue > *mid)end = mid;elsebeg = mid + 1;  //在mid之后查找mid = beg + (end - beg) / 2;   //新的中间点}}return fr;}/// <summary>/// 查找元素是否存在,或者计算元素个数。/// 例:/// _DList<int> d1 = { 1,3,4,5,3 };/// size_t n;/// 执行: alg.IsExistsElement(d1, 3, &n, true)) 则 n = 2, 并且函数返回true /// alg.IsExistsElement(d1, 3), 函数返回true /// </summary>/// <typeparam name="CollectionClass">集合类型</typeparam>/// <typeparam name="Element_Type">集合元素类型</typeparam>/// <param name="col">集合</param>/// <param name="Value">元素值</param>/// <param name="pCount">保存元素个数的变量指针</param>/// <param name="IsStatisticsCount">是否计算出现个数</param>/// <returns></returns>/// 创建时间: 2024-07-30     最后一修改时间:2024-07-30  (初步测试)template<typename CollectionClass,typename Element_Type>bool IsExistsElement(const CollectionClass& col, const Element_Type &Value,size_t* pCount = null, const bool &IsStatisticsCount = false){size_t nSize = col.size();auto itBegin = col.begin();if (IsStatisticsCount){assert(pCount != null);*pCount = 0;for (size_t n = 0; n < nSize; ++n) {if (*(itBegin + n) == Value){*pCount = *pCount + 1;}			}return *pCount != 0;}else{for (size_t n = 0; n < nSize; ++n){if (*(itBegin + n) == Value)return true;}return false;}	}/// <summary>/// 检查母集合中是否存在子集./// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <param name="itParentBegin">母集开始位置</param>/// <param name="itParentEnd">>母集结束位置</param>/// <param name="itSubBegin">子集开始位置</param>/// <param name="itSubEnd">子集结束位置</param>/// <returns></returns>/// 创建时间: 2024-07-24     最后一修改时间:2024-07-24  (初步测试)template<typename IteratorClass>bool IsContain(const IteratorClass& itParentBegin, const IteratorClass& itParentEnd, const IteratorClass& itSubBegin,const IteratorClass& itSubEnd) {//母串集合元集size_t nParentSize = itParentEnd - itParentBegin;//字串集合元素size_t nSubSize = itSubEnd - itSubBegin;if (nSubSize == 0 || nParentSize == 0 || nSubSize > nParentSize) return false;for (size_t i = 0; i < nParentSize - nSubSize + 1; ++i) {bool isSub = true;for (size_t j = 0; j < nSubSize; ++j){if ( *(itParentBegin + i + j) != *(itSubBegin + j) ) {isSub = false;break;}}if (isSub) return true;}return false;}/*/// <summary>/// 检查母集合中是否存在子集./// </summary>/// <param name="vecParent">母集</param>/// <param name="vecSub">子集</param>/// <returns></returns>/// 创建时间: 2024-07-24     最后一修改时间:2024-07-24  (初步测试)inline bool IsContain(const std::vector<int>& vecParent, const std::vector<int>& vecSub){if (vecParent.size() == 0 || vecSub.size() == 0 || vecSub.size() > vecParent.size())return false;for (size_t i = 0; i < vecParent.size() - vecSub.size() + 1; ++i) {bool bFind = true;for (size_t j = 0; j < vecSub.size(); ++j) {if (vecParent[i + j] != vecSub[j]) {bFind = false;break;}}if (bFind) return true;}return false;}*//// <summary>/// 检查母集合colParent中是否存在子集colSub。/// </summary>/// <typeparam name="CollectionClass"></typeparam>/// <param name="colParent"></param>/// <param name="colSub"></param>/// <returns></returns>/// 创建时间: 2024-07-25     最后一修改时间:2024-07-25  (初步测试)template<typename CollectionClass>bool IsContain(const CollectionClass& colParent, const CollectionClass& colSub) {//母串集合元集size_t nParentSize = colParent.size();auto itParentBegin = colParent.begin();auto itSubBegin = colSub.begin();//字串集合元素size_t nSubSize = colSub.size();	if (nSubSize == 0 || nParentSize == 0 || nSubSize > nParentSize) return false;for (size_t i = 0; i < nParentSize - nSubSize + 1; ++i) {bool isSub = true;for (size_t j = 0; j < nSubSize; ++j) {if (*(itParentBegin + i + j) != *(itSubBegin + j)) {isSub = false;break;}}if (isSub) return true;}return false;}/***************************************************************FindFirstOf使用例子代码:_string s1 = "(int)";_string s2 = "int";auto s = FindFirstOf(s1.begin(), s1.end(), s2.begin(), s2.end());if (s != null)_cout << s;输出:int)***************************************************************//// <summary>/// 查找一段数据第一次出现的位置。/// </summary>/// <typeparam name="T">数据类型</typeparam>/// <param name="itParentBegin">母数据指针开始位置</param>/// <param name="itParentEnd">母数据开始结束位置,对于字符串,即:psz + strLength </param>/// <param name="itSubBegin">子数据指针开始位置</param>/// <param name="itSubEnd">子数据开始结束位置,对于字符串,即:psz + strLength </param>/// <returns>如找到,返回这段数据第一次出现的指针位置,否则返回nuLL。</returns>/// 创建时间: 2024-08-15     最后一修改时间:2024-08-15  (已测试)template<typename Iterator>inline Iterator findFirstOf(const Iterator& itParentBegin, const Iterator& itParentEnd,const Iterator& itSubBegin, const Iterator& itSubEnd) {const int nParentLength = itParentEnd - itParentBegin;const int nSubLength = itSubEnd - itSubBegin;if (nSubLength <= 0 || nSubLength > nParentLength) return Iterator();Iterator Result = itParentBegin;//别忘了加上1const Iterator end = itParentBegin + nParentLength - nSubLength + 1;while (Result != end) {bool bFind = true;//判断这一段数据是否相等for (int n = 0; n < nSubLength; ++n) {if (*(Result + n) != *(itSubBegin + n)) {bFind = false;break;}}if (bFind) return Result;++Result;}return Iterator();}/// <summary>/// /// </summary>/// <typeparam name="T"></typeparam>/// <param name="beginPtr"></param>/// <param name="endPtr"></param>/// <param name="p"></param>/// <returns></returns>/// 创建时间: 2024-08-15     最后一修改时间:2024-08-15  (已测试)template<class IterClass>inline bool findPairOfFirst(const IterClass& itBegin, const IterClass& itEnd,PairOf<IterClass>& p){//查找左边第一次出现的位置p.itLeftPosition = findFirstOf(itBegin, itEnd, p.itLeft, p.itLeft + p.LeftLength);//查找右边第一次出现我if (p.itLeftPosition != null){p.itRigthPosition = FindFirstOf(p.itLeftPosition + p.LeftLength, itEnd, p.itRight,p.itRight + p.RigthLength);}return p.itLeftPosition != null && p.itRigthPosition != null;}/// <summary>/// 问题:用C++写出 用二分法查找有序容器的插入点	/// /// 用二分法查找插入点,迭代器要支持 +,- >=、<=/// 不支持 std::list/// 支持 std::vector, lf::DList/// /// 例子:///		_list<int> lst1{0,2,4,5,6,7,8};	 ///		_list<int> lst2{ 8,7,6,5,4,3,2,1};///		_list<int> a1;///		_list<int> a2 = {1};/// ///		alg.find_binary_insert_pos(lst1.begin(), lst1.end(), 0,true)=1///		alg.find_binary_insert_pos(lst1.begin(), lst1.end(), 3, true) = 2///		alg.find_binary_insert_pos(lst1.begin(), lst1.end(), -9, true) = 0///		alg.find_binary_insert_pos(lst2.begin(), lst2.end(), 1, false) = 7///		alg.find_binary_insert_pos(lst2.begin(), lst2.end(), 3, false) = 5///		alg.find_binary_insert_pos(lst2.begin(), lst2.end(), -1, false) = 8///		alg.find_binary_insert_pos(lst2.begin(), lst2.end(), 9, false) = 0///		alg.find_binary_insert_pos(a1.begin(), a1.end(), 9, false) = 0///		alg.find_binary_insert_pos(a2.begin(), a2.end(), 9, true) = 1/// /// </summary>/// <typeparam name="IterClass"></typeparam>/// <typeparam name="ElemType"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="etValue"></param>/// <param name="bAscending">是否升序</param>/// <returns></returns>/// 创建时间: 2024-10-27     最后一修改时间:2024-10-27  (已测试) (花了一整天时间,七小时)template<class IterClass, class ElemType>inline size_t find_binary_insert_pos(const IterClass& itBegin, const IterClass& itEnd,const ElemType& etValue, const bool& bAscending = true){/*迅飞星火:int binarySearchInsertPosition(const std::vector<int>& arr, int target) {int left = 0;int right = arr.size() - 1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == target) {return mid; // 如果找到目标值,返回其索引}else if (arr[mid] < target) {left = mid + 1; // 目标值在右侧子数组中}else {right = mid - 1; // 目标值在左侧子数组中}}// 如果没有找到目标值,返回应该插入的位置return left;}天工:#include <iostream>#include <vector>#include <algorithm>int main() {std::vector<int> sorted_vector = {1, 3, 4, 6, 8, 9, 10, 12};int value_to_insert = 7;// 使用 std::lower_bound 找到插入点auto insert_point = std::lower_bound(sorted_vector.begin(), sorted_vector.end(), value_to_insert);// 输出插入点(索引)std::cout << "The value " << value_to_insert << " should be inserted at index " << (insert_point - sorted_vector.begin()) << std::endl;return 0;}*/if (itEnd == itBegin) return 0;lassert(itEnd > itBegin, "find_binary_insert_pos");			size_t nLength = itEnd - itBegin;size_t mid = nLength / 2;if (bAscending) {  //升序while (mid < nLength && mid >= 0) {IterClass it = itBegin + mid;			 if (*it < etValue) {if (mid != nLength - 1) {if (*(it + 1) >= etValue) {return mid + 1;}else {  //在右边继续找mid = mid + (nLength - mid) / 2;}}else {return nLength;}	 	}else if (*it > etValue) {if (mid != 0) {if (*(it - 1) <= etValue) {return mid;}else { //在左边继续找mid = mid - (mid + 1) / 2;}}else{return 0;}			}else {return mid;}} }else{ //降序		while (mid < nLength && mid >= 0) {		   IterClass it = itBegin + mid;				  if( *it > etValue ) { 					if (mid != nLength - 1) { //可能不支持 >=if (*(it + 1) <= etValue) {return mid + 1;}else {  //在右边继续找mid = mid + (nLength - mid) / 2;}}else{return nLength;}}else if (*it < etValue) {if (mid != 0) {if (*(it - 1) >= etValue) {return mid;}else { //在左边继续找mid = mid - (mid + 1) / 2;}}else {return 0;}}else {return mid;}				 }		 }		throw("无法找到插入位置,算法错误!");}/// <summary>/// 用二分法查找有序容器的插入点,如果容器中存在同样的元素,/// 则返回npos./// 迭代器要支持 +,- >=、<=。/// </summary>/// <typeparam name="IterClass"></typeparam>/// <typeparam name="ElemType"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="etValue"></param>/// <param name="bAscending"></param>/// <returns></returns>/// 创建时间: 2024-10-27     最后一修改时间:2024-10-27  (已测试) (花了一整天时间,七小时)template<class IterClass, class ElemType>inline size_t find_binary_insert_unique_pos(const IterClass& itBegin, const IterClass& itEnd,const ElemType& etValue, bool bAscending = true) {if (itEnd == itBegin) return 0;lassert(itEnd > itBegin, "find_binary_insert_unique_pos");size_t nLength = itEnd - itBegin;size_t mid = nLength / 2;if (bAscending) {  //升序while (mid < nLength && mid >= 0) {IterClass it = itBegin + mid;if (*it < etValue) {if (mid != nLength - 1) {if (*(it + 1) == etValue) {return _Math::npos;}else if (*(it + 1) > etValue) {return mid + 1;}else {  //在右边继续找mid = mid + (nLength - mid) / 2;}}else {return nLength;}}else if (*it > etValue) {if (mid != 0) {if (*(it + 1) == etValue) {return _Math::npos;}else if(*(it - 1) < etValue) {return mid;}else { //在左边继续找mid = mid - (mid + 1) / 2;}}else {return 0;}}else {return _Math::npos;}}}else { //降序		while (mid < nLength && mid >= 0) {IterClass it = itBegin + mid;if (*it > etValue) {if (mid != nLength - 1) {if (*(it + 1) == etValue) {return _Math::npos;}else if (*(it + 1) < etValue) {return mid + 1;}else {  //在右边继续找mid = mid + (nLength - mid) / 2;}}else {return nLength;}}else if (*it < etValue) {if (mid != 0) {if (*(it + 1) == etValue) {return _Math::npos;}else if (*(it - 1) > etValue) {return mid;}else { //在左边继续找mid = mid - (mid + 1) / 2;}}else {return 0;}}else {return _Math::npos;}}}throw("无法找到插入位置,算法错误!");		   }/// <summary>/// 获取配对中间的数据,例 (a): for(int i) = 0 ,如果是括号为配对,/// 那么获取的数据是 "a" 和 "int i" 。/// </summary>/// <typeparam name="T"></typeparam>/// <param name="beginPtr"></param>/// <param name="endPtr"></param>/// <param name="p"></param>/// <returns></returns>/// 创建时间: 2024-08-15     最后一修改时间:2024-08-15  (已测试)template<class Iterator>auto extractionPairData(const Iterator& itBegin, const Iterator& itEnd, PairOf<Iterator>& p){using T = std::remove_reference_t<decltype(*itBegin)>;_DList<_Array<T>> result;auto f = FindPairOfFirst(itBegin, itEnd, p);while (f){result.Add(p.PairOnlyData());f = FindPairOfFirst(p.itRigthPosition + p.RigthLength, itEnd, p);}return result;}template<class CollectionClass, class ValueType>_DList<CollectionClass> extractionPairData(const CollectionClass& col,const CollectionClass left, const CollectionClass& right) {		 _DList<CollectionClass> result;/*auto f = FindPairOfFirst(itBegin, itEnd, p);while (f){result.Add(p.PairOnlyData());f = FindPairOfFirst(p.itRigthPosition + p.RigthLength, itEnd, p);}*/return result;}/// <summary>/// 计数colParent包含有多少个colSub,跟IsContain算法一样,但是/// IsContain找到立即返回。/// </summary>/// <typeparam name="CollectionClass">具有迭代性质的类</typeparam>/// <param name="colParent">母集合</param>/// <param name="colSub">子集合</param>/// <returns></returns>/// 创建时间: 2024-07-29     最后一修改时间:2024-07-29  template<typename CollectionClass>int count(const CollectionClass &colParent, const CollectionClass &colSub) {int nResult = 0;//母串集合元集size_t nParentSize = colParent.size();auto itParentBegin = colParent.begin();auto itSubBegin = colSub.begin();//字串集合元素size_t nSubSize = colSub.size();if (nSubSize == 0 || nParentSize == 0 || nSubSize > nParentSize) return false;for (size_t i = 0; i < nParentSize - nSubSize + 1; ++i) {bool isSub = true;for (size_t j = 0; j < nSubSize; ++j) {if (*(itParentBegin + i + j) != *(itSubBegin + j)) {isSub = false;break;}}if (isSub) ++nResult;	 				}return nResult;}////// <summary>/// 对列表的每一项计数,返回关联容器(项,出现次数)/// </summary>/// <typeparam name="CollectionClass"></typeparam>/// <typeparam name="value_type"></typeparam>/// <param name="col"></param>/// <returns></returns>/// 创建时间: 2024-11-16     最后一修改时间:2024-11-16  template<typename value_type, typename CollectionClass = std::list<value_type>>std::map<value_type,size_t> count(const CollectionClass& col) {std::map<value_type, size_t> m;for (const value_type& v : col) {++m[v];}		return m;}/// <summary>/// 打印计数/// 例子:///		vector<int> vec = { 1,3,5,9,5,2,0 };/// 	alg.count_print<int>(vec);/// </summary>/// <typeparam name="value_type"></typeparam>/// <typeparam name="list_type"></typeparam>/// <param name="sl"></param>/// 创建时间: 2024-11-16     最后一修改时间:2024-11-16  template<typename value_type, typename list_type = std::list<value_type>>void count_print(const list_type& sl) {if (sl.size() == 0) return;auto m = count<value_type>(sl);/*auto c = (*sl.begin())[0];if ( typeid(c) == typeid(wchar_t) ){for (const auto& p : m)  //对map中的每个无素std::wcout << p.first << _t("\t\t") << p.second << std::endl;//打印结果}else{for (const auto& p : m)  //对map中的每个无素std::cout << p.first << "\t\t" << p.second << std::endl;//打印结果}*/for (const auto& p : m)  //对map中的每个无素				std::cout << p.first << "\t\t" << p.second << std::endl;//打印结果}/// <summary>/// 打印计数/// 用法:/// 	std::list<std::wstring> ss1 = { _t("if"),_t("for"),_t("for"),_t("int")};/// 	std::list<std::string> ss2 = { "if","for" ,"for","int" };/// 	alg.word_count_print<wstring>(ss1);/// 	alg.word_count_print<string>(ss2);/// /// </summary>/// <typeparam name="list_type"></typeparam>/// <typeparam name="value_type"></typeparam>/// <param name="sl"></param>/// 创建时间: 2024-11-16     最后一修改时间:2024-11-16  template<typename value_type,typename list_type = std::list<value_type>>void word_count_print(const list_type& sl) {if (sl.size() == 0) return;		auto m = count<value_type>(sl);for (const auto& p : m)  //对map中的每个无素				{mf::_cout_s(p.first);std::cout <<"\t\t"<< p.second << std::endl;//打印结果}}/// <summary>/// 标准库定义了一个名为count_if的算法。类似find_if,此函数接受/// 一对迭代器,表示一个输入范围,还接受一个谓词,会对输入范围内每个元素执行。/// cout_if返回一个计数值,表示谓词有多少次为真。/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// <returns></returns>/// 创建时间: 2024-10-15     最后一修改时间:2024-10-15  template<typename IteratorClass, typename ComparingFunctions>size_t count_if(const IteratorClass& itBegin, const IteratorClass& itEnd,const ComparingFunctions& f) {size_t nResult = 0;for (auto it = itBegin; it != itEnd; ++it) {if (f(*it))++nResult;}return nResult;}////// <summary>/// 如果是数组:/// 	int ia[] = { 1,2,3,4,5 };///		accumulate(ia + 0, ia + 5, 0);/// /// accumulate的第三个参数的类型决定了函数中使用哪个加法运算符以及返回值的类型/// </summary>/// <typeparam name="value_type"></typeparam>/// <typeparam name="IterClass"></typeparam>/// <param name="begin"></param>/// <param name="end"></param>/// <param name="InitialValue"></param>/// <returns></returns>/// 创建时间: 2024-10-07     最后一修改时间:2024-10-07  template<class IterClass, class value_type>static value_type accumulate(const IterClass& begin,const IterClass& end,const value_type& InitialValue) {value_type sum = InitialValue; size_t n = 0;while (begin + n < end){sum += *(begin + n);++n;}return sum;}/// <summary>/// /// </summary>/// <typeparam name="IterClass"></typeparam>/// <param name="begin1"></param>/// <param name="end1"></param>/// <param name="begin2"></param>/// <returns></returns>/// 创建时间: 2024-10-07     最后一修改时间:2024-10-07  template<class IterClass>static bool equal(const IterClass& begin1,const IterClass& end1,const IterClass& begin2) {size_t n = 0;while (begin1 + n < end1){if (*(begin1 + n) != *(begin2 + n))return false;++n;}return true;}/// <summary>/// /// </summary>/// <typeparam name="IterClass"></typeparam>/// <typeparam name="value_type"></typeparam>/// <param name="begin"></param>/// <param name="end"></param>/// <param name="tFill"></param>/// 创建时间: 2024-10-07     最后一修改时间:2024-10-07  template<class IterClass, class value_type>static void fill(const IterClass& begin,const IterClass& end,const value_type& tFill = value_type()) {size_t n = 0;while (begin + n < end){*(begin + n) = tFill;++n;}		 }/// <summary>/// /// </summary>/// <typeparam name="IterClass"></typeparam>/// <typeparam name="value_type"></typeparam>/// <param name="begin"></param>/// <param name="nCount"></param>/// <param name="tFill"></param>/// 创建时间: 2024-10-07     最后一修改时间:2024-10-07  template<class IterClass, class value_type>static void fill_n(const IterClass& begin,const size_t& nCount,const value_type& tFill = value_type()) {size_t n = 0;/*for(size_t n = 0; n < nCount; ++n){*(begin + n) = tFill;	}*/IterClass it = begin;for (size_t n = 0; n < nCount; ++n){*(it) = tFill;it++;}}/// <summary>/// /// </summary>/// <typeparam name="T"></typeparam>/// <param name="begin"></param>/// <param name="end"></param>/// <param name="dest"></param>/// <returns></returns>/// 创建时间: 2024-10-07     最后一修改时间:2024-10-07  template<class T>const T* copy(const T* begin, const T* end, T* dest) {T* it1 = (T*)begin;T* it2 = dest;while (it1 < end) {*it2++ = *it1++;		}return it2;}/// <summary>/// 例子:/// int main() {/// 	vector<int> vec = { 1,2,3,4 };/// 	ostream_iterator<int> out_iter(cout, " ");/// 	alg.copy(vec.begin(), vec.end(), out_iter);/// 	cout << endl;/// 	return 0;/// }/// /// 输出:///		1 2 3 4/// /// </summary>/// <typeparam name="InIter"></typeparam>/// <typeparam name="OutIter"></typeparam>/// <param name="begin"></param>/// <param name="end"></param>/// <param name="dest"></param>/// <returns></returns>/// 创建时间: 2024-10-18     最后一修改时间:2024-10-18  template<class InIter, class OutIter>OutIter copy(InIter begin, InIter end, OutIter dest) {/** std::源码:_EXPORT_STD template <class _InIt, class _OutIt>_CONSTEXPR20 _OutIt copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) to [_Dest, ...)_STD _Adl_verify_range(_First, _Last);const auto _UFirst = _STD _Get_unwrapped(_First);const auto _ULast  = _STD _Get_unwrapped(_Last);const auto _UDest  = _STD _Get_unwrapped_n(_Dest, _STD _Idl_distance<_InIt>(_UFirst, _ULast));_STD _Seek_wrapped(_Dest, _STD _Copy_unchecked(_UFirst, _ULast, _UDest));return _Dest;}*/while (begin < end) {*dest++ = *begin++;}return dest;}/// <summary>///	例子://////		string s = "abcda-";//////		_list<int> ilst1 = { 3,5,0,130,0 };///		list<int> ilst2 = { 3,5,0,130,0 };//////		//将所有值为0的元素改为42///		alg.replace(ilst1.begin(), ilst1.end(), 0, 42);///		alg.replace(ilst2.begin(), ilst2.end(), 0, 42);//////		char sz[] = "abcda";//////		alg.replace(s.begin(), s.end(), 'a', 'w');///		alg.replace(&sz[0], sz + 5, 'a', 'w');//////		_pn(ilst1);///		_pn(ilst2);///		_pn(s);///		_pn(sz);//////	输出://////		ilst1={3,5,42,130,42}///		ilst2={3,5,42,130,42}///		s="wbcdw-"///		sz="wbcdw"//////		/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="value_type"></typeparam>/// <param name="begin"></param>/// <param name="end"></param>/// <param name="old_value"></param>/// <param name="new_value"></param>/// 创建时间: 2024-10-08     最后一修改时间:2024-10-08  template<class itClass,class value_type>void replace(const itClass& begin, const itClass& end, const value_type& old_value,const value_type& new_value) {//itClass it =  begin;itClass it =  begin; //这里要 != ,不能 while (it < end) 因为在链表中,可能不会重载小于运算符while (it != end) {if (*it == old_value) {				*it = new_value;}it++;}		 		}/// <summary>///  注意:std::replace_copy第三个参数为 back_inserter/// 例子:///		list<int> ilst = { 0, 1,2,3 };///		vector<int> ivec{ 3,3 };//////		std:///		///		//使用back_inserter按需要增长目标序列///		//replace_copy(ilst.cbegin(), ilst.cend(),///		//	back_inserter(ivec), 0, 42);///		/// ///		alg.replace_copy(ilst.cbegin(), ilst.cend(), ivec, 0, 42);///		_pn(ilst);///		_pn(ivec);///	输出:///		ilst={0,1,2,3}///		ivec = { 3,3,42,1,2,3 }/// </summary>/// <typeparam name="itClass"></typeparam>/// <typeparam name="container_class"></typeparam>/// <typeparam name="value_type"></typeparam>/// <param name="begin"></param>/// <param name="end"></param>/// <param name="cc"></param>/// <param name="old_value"></param>/// <param name="new_value"></param>/// <returns></returns>/// 创建时间: 2024-10-08     最后一修改时间:2024-10-08 template<class itClass, class container_class, class value_type>container_class& replace_copy(const itClass& begin, const itClass& end,container_class& cc,const value_type& old_value,const value_type& new_value) {//itClass it =  begin;itClass it = begin;//这里要 != ,不能 while (it < end) 因为在链表中,可能不会重载小于运算符while (it != end) {if (*it == old_value) {cc.push_back(new_value);}else{cc.push_back(*it);}it++;}return cc;}/// <summary>/// 返回一个unique的拷贝,注意,如果已排序的集合速度会很快。/// </summary>/// <typeparam name="container_class"></typeparam>/// <param name="cCopy"></param>/// <param name="is_sorted"></param>/// <returns></returns>/// 创建时间: 2024-10-08     最后一修改时间:2024-10-08 template<class container_class>container_class unique_copy(const container_class& cCopy, bool is_sorted = false) {container_class cResult;if (cCopy.size() == 0) return cResult;auto it = cCopy.begin(), itend = cCopy.end();if (is_sorted) {cResult.push_back(*it);it++;			 while (it != itend) {if (*it != *(cResult.end() - 1)) {cResult.push_back(*it);}it++;}}else {			 while (it != itend) {if (!IsExists(cResult, *it)) {cResult.push_back(*it);}it++;}}	return cResult;}////// <summary>/// find_if 是一个在 C++ 标准库 <algorithm> 头文件中定义的函数模板,用于/// 在一个范围内查找满足特定条件的第一个元素。它的原型如下/// /// template <class InputIterator, class UnaryPredicate>///	InputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate p);/// /// first:范围的起始迭代器。/// last:范围的结束迭代器。///	p:一个一元谓词函数,用于判断元素是否满足条件。/// /// find_if 函数返回一个指向满足条件的第一个元素的迭代器,如果没有找到满足条件的元素,则返回 last/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// <returns></returns>/// 创建时间: 2024-10-12     最后一修改时间:2024-10-12 template<typename IteratorClass, typename ComparingFunctions>IteratorClass find_if(const IteratorClass& itBegin, const IteratorClass& itEnd, ComparingFunctions f) {/*_EXPORT_STD template <class _InIt, class _Pr>_NODISCARD _CONSTEXPR20 _InIt find_if(_InIt _First, const _InIt _Last, _Pr _Pred) { // find first satisfying _Pred_STD _Adl_verify_range(_First, _Last);auto _UFirst      = _STD _Get_unwrapped(_First);const auto _ULast = _STD _Get_unwrapped(_Last);for (; _UFirst != _ULast; ++_UFirst) {if (_Pred(*_UFirst)) {break;}}_STD _Seek_wrapped(_First, _UFirst);return _First;}*/for (; itBegin != itEnd; ++itBegin) {if (f(*itBegin)) {return itBegin;		}}return itEnd;}/// <summary>/// 从后面开始查找 [itBegin,itEnd) 第一个符合条件的元素,如找不到,返回itEnd;/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// <returns></returns>/// 创建时间: 2024-10-12     最后一修改时间:2024-10-12  (已测试)template<typename IteratorClass, typename ComparingFunctions>IteratorClass rfind_if(const IteratorClass& itBegin, const IteratorClass& itEnd, ComparingFunctions f) {if (itBegin != itEnd) {for (auto it = itEnd - 1; it != itBegin; it--) {if (f(*it))return it;}	//没找到,看看第一个元素是否符合if (f(*itBegin))return itBegin;}return itEnd;}/// <summary>/// 标准库定义了名为partition的算法,它接受一个谓词,对容器内容进/// 行划分,使得谓词为true的值会排在容器的前半部分,而使谓词为false的值会排/// 在后半部分。算法返回一个迭代器,指向最后一个使谓词为true的元素之后的位置。/// /// 例子:/// 	 ///		vector<string> a = { "for","int","double","if" ,"throw" };//////		std::partition(a.begin(), a.end(), [](const string& s)->bool {///			return s.size() >= 5;///		});//////		_pn(a);////// 输出:/// ///		a={"throw","double","int","if","for"}/// /// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="ComparingFunctions"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// <returns></returns>/// 创建时间: 2024-10-12     最后一修改时间:2024-10-12  (已测试)template<typename IteratorClass, typename ComparingFunctions>IteratorClass partition(IteratorClass itBegin, IteratorClass itEnd, ComparingFunctions f) {//--------------------------------算法1/*IteratorClass itResult = itEnd;while (itBegin != itEnd) {if (!f(*itBegin)) { //还有优化可能,因为向后移时,itBegin每次都被比较auto it = this->find_if(itBegin + 1, itEnd,f);if (it != itEnd) {					this->Swap(itBegin, it);itResult = itBegin; //保留最后一个位置}else {return itResult;}}itBegin++;}return itResult;*///--------------------------------算法2 (结果跟std::partition相同)if (itBegin != itEnd) {IteratorClass itFindEnd = itEnd;//itBegin != itFindEnd 很关键for (; itBegin != itFindEnd; itBegin++) {//执行次数与满足f条件的元素的个数相同//std::cout << "*itBegin=" << *itBegin << "\n";if (!f(*itBegin)) {IteratorClass itFind = this->rfind_if(itBegin + 1, itFindEnd, f);if (itFind != itFindEnd) {						//std::cout << "*itFindEnd=" << *itFind << "\n";itFindEnd = itFind;this->Swap(itBegin, itFind);											}else {return itFindEnd;}}}//算法返回一个迭代器,指向最后一个使谓词为true的元素之后的位置。return itFindEnd;}return itEnd;}////// <summary>/// C++ 中的 for_each 是一个标准模板库 (STL) 算法,用于对容器中的每个元素执行指定的操作。/// 这个操作可以是一个函数、一个函数对象或一个 Lambda 表达式。/// /// 例子:/// 	std::vector<int> nums = { 1, 2, 3, 4, 5 };//////		std::for_each(nums.begin(), nums.end(), [](int n) {///			std::cout << n * 2 << "\t";///		});/// /// 输出:/// ///		2       4       6       8       10/// /// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="FunctionClass"></typeparam>/// <param name="itBegin"></param>/// <param name="itEnd"></param>/// <param name="f"></param>/// <returns></returns>/// 创建时间: 2024-10-13     最后一修改时间:2024-10-13  (已测试)template<typename IteratorClass, typename FunctionClass>FunctionClass for_each(const IteratorClass& itBegin, const IteratorClass& itEnd,const FunctionClass &f) {for (auto it = itBegin; it != itEnd; it++) {f(*it);}return f;}/// <summary>/// std::lower_bound 是 C++ 标准库中的一个函数,用于在有序范围内进行二分查找,/// 以找到第一个不小于给定值的元素。它位于 <algorithm> 头文件中。查找的数据必须/// 是从小到大排列。/// 注意事项///		(1)	范围必须是有序的:std::lower_bound 假设范围已经按非递减顺序(升序)排序。///			如果范围未排序,结果将不可预测。/// ///		(2)	复杂度:由于 std::lower_bound 使用二分查找算法,时间复杂度为 O(log n),///			其中 n 是范围内的元素数量。/// ///		(3)	返回类型:返回的是迭代器类型,可以是任何满足前向迭代器要求的迭代器类型,///			如 std::vector<T>::iterator、std::array<T, N>::iterator 或者普通指针。/// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="value_type"></typeparam>/// <param name="first"></param>/// <param name="last"></param>/// <param name="val"></param>/// <returns></returns>/// 创建时间: 2024-11-04    最后一修改时间: 2024-11-11  (已测试)template <class IteratorClass, class value_type>IteratorClass lower_bound(IteratorClass first, IteratorClass last, const value_type& val) {/*例子:int main() {vector<int> a1 = { 0,1,2,3,4,5 };vector<int> a2 = {1,2,3,4};_pn(*std::lower_bound(a1.begin(), a1.end(), 3));_pn(*alg.lower_bound(a1.begin(), a1.end(), 3));auto it1 = std::lower_bound(a2.begin(), a2.end(), 4);if (it1 != a2.end()) {_pn(*it1);}it1 = alg.lower_bound(a2.begin(), a2.end(), 4);if (it1 != a2.end()) {_pn(*it1);}return 0;}/*//*for (auto it = first; it != last; it++) {if (*it >= val)return it;} return last;*///1 2,4,5,6   3auto left = first, right = last;while (left != right) {auto mid = left + (right - left) / 2;if (*mid >= val) {if (mid == first) //检查是不是第一个元素return first;if (*(mid - 1) < val)  //检查前面一个return mid;right = mid;  //在左边找}else{if (mid == last - 1) //检查是否最后一个元素return last;left = mid;  //在右边找}		}return last;}/// <summary>/// 返回一个迭代器,指向第一个大于val的元素。/// 例子:///		int main() {    //////			vector<int> a1 = { 0,3,3,5,6 };//////			auto it1 = alg.lower_bound(a1.begin(), a1.end(), 3);//////			auto it2 = alg.upper_bound(a1.begin(), a1.end(), 3);//////			while (it1 != it2) {///			_pn(*it1);///			++it1;///		}///		return 0;///		}/// 输出:///		*it1 = 3///		*it1 = 3/// /// </summary>/// <typeparam name="IteratorClass"></typeparam>/// <typeparam name="value_type"></typeparam>/// <param name="first"></param>/// <param name="last"></param>/// <param name="val"></param>/// <returns></returns>/// 创建时间: 2024-11-11    最后一修改时间: 2024-11-11  (已测试)template <class IteratorClass, class value_type>IteratorClass upper_bound(IteratorClass first, IteratorClass last, const value_type& val) {auto left = first, right = last;while (left != right) {auto mid = left + (right - left) / 2;if (*mid > val) {if (mid == first) //检查是不是第一个元素return first;if (*(mid - 1) <= val)  //检查前面一个return mid;right = mid;  //在左边找}else {if (mid == last - 1) //检查是否最后一个元素return last;left = mid;  //在右边找}}return last;}///}alg;  //类实例///_LF_END_  //--------------------------- namespace lf///

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/60956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytest | 框架的简单使用

这里写目录标题 单个文件测试方法执行测试套件的子集测试名称的子字符串根据应用的标记进行选择 其他常见的测试命令 pytest框架的使用示例 pytest将运行当前目录及其子目录中test_*.py或 *_test.py 形式的所有 文件 文件内的函数名称可以test* 或者test_* 开头 单个文件测试…

【C++】类和对象-深度剖析默认成员函数-上

> &#x1f343; 本系列为初阶C的内容&#xff0c;如果感兴趣&#xff0c;欢迎订阅&#x1f6a9; > &#x1f38a;个人主页:[小编的个人主页])小编的个人主页 > &#x1f380; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 > ✌️ &#x1f91e; &#x1…

Web性能优化:从基础到高级

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Web性能优化&#xff1a;从基础到高级 Web性能优化&#xff1a;从基础到高级 Web性能优化&#xff1a;从基础到高级 引言 基础优…

当 docker-compose.yaml 文件部署时,Dify 线上版本升级过程

如果线上 Dify 是通过 docker-compose.yaml 文件部署的&#xff0c;那么当 Dify 版本升级时该如何操作呢&#xff1f;官方已经给出了 Docker compose 和 Source Code 两种方式。相对而言&#xff0c;前者更简单些&#xff0c;至少不需要安装依赖包和迁移数据库文件。为了更加具…

如何让手机ip变成动态

在数字化浪潮中&#xff0c;手机已成为我们日常生活中不可或缺的一部分。无论是浏览网页、使用社交媒体还是进行在线购物&#xff0c;手机都扮演着举足轻重的角色。然而&#xff0c;在享受网络带来的便利时&#xff0c;我们也需要关注网络安全和隐私保护。静态IP地址可能让手机…

vue3 如何调用第三方npm包内部的 pinia 状态管理库方法

抛砖引玉: 如果在开发vue3项目是, 引用了npm第三方包 ,而且这个包内使用了Pinia 状态管理库,那我们如何去调用 npm内部的 Pinia 状态管理库呢? 实际遇到的问题: 今天在制作npm包时遇到的问题,之前Vue2版本的时候状态管理库用的Vuex ,当时调用npm包内的状态管理库很简单,直接引…

Linux笔记---调试工具GDB(gdb)

1. gdb的概念 GDB&#xff0c;全称GNU Debugger&#xff0c;是一个功能强大的开源调试工具&#xff0c;广泛用于Unix和类Unix系统&#xff0c;以及Microsoft Windows和macOS平台。GDB允许开发者在程序执行过程中查看内部运行情况&#xff0c;帮助定位和修复程序中的错误。 gd…

编译器gcc/g++

gcc 只用来编译C g 编译C/C 1.预处理&#xff08;进行宏替换/去注释/条件编译/头文件展开等&#xff09; 先创建 code.c 文件 -E --> 从现在开始&#xff0c;进行程序的翻译&#xff0c;一旦预处理做完&#xff0c;就停下来 -o --> 表明 -o 后面的文件名称 code…

一.安装版本为19c的Oracle数据库管理系统(Oracle系列)

1.数据库版本信息&#xff1a; 版本信息&#xff1a; 或者直接由命令查出来&#xff1a; 2.操作系统的版本信息 3.安装包下载与上传 可以去oracle官网下载也可以从其他人的百度网盘链接中下载&#xff1a; 使用xftp工具或者其他的工具&#xff08;mobaxterm&#xff09;上传到l…

DimensionX 部署笔记

目录 生成视频用CogVideoX-5b-I2V 推理代码&#xff1a; DimensionX 生成视频用CogVideoX-5b-I2V 推理代码&#xff1a; 可以生成&#xff0c;从左向右旋转的&#xff0c;也可以生成从上往下旋转的&#xff1a; import torch from diffusers import CogVideoXImageToVideo…

uni-app移动端与PC端兼容预览PDF文件

过程遇到的问题 1、如果用的是最新的版本的pdfjs的话&#xff0c;就会报Promise.withResolvers 不是一个方法的错误&#xff0c;原因是Promise.withResolvers是ES15新特性&#xff0c;想了解可参考链接&#xff0c;这里的解决方案是将插件里的涉及到Promise.withResolvers的地…

Node.js | Yarn下载安装与环境配置

一、安装Node.js Yarn 是 Node.js 下的包管理工具&#xff0c;因此想要使用 Yarn 就必须先下载 Node.js。 推荐参考&#xff1a;Node.js | npm下载安装及环境配置教程 二、Yarn安装 打开cmd&#xff0c;输入以下命令&#xff1a; npm install -g yarn检查是否安装成功&…

开源TTS语音克隆神器GPT-SoVITS_V2版本地整合包部署与远程使用生成音频

文章目录 前言1.GPT-SoVITS V2下载2.本地运行GPT-SoVITS V23.简单使用演示4.安装内网穿透工具4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 本文主要介绍如何在Windows系统电脑使用整合包一键部署开源TTS语音克隆神器GPT-SoVITS&#xff0c;并结合cpolar内网穿透工…

[Docker#11] 容器编排 | .yml | up | 实验: 部署WordPress

目录 1. 什么是 Docker Compose 生活案例 2. 为什么要使用 Docker Compose Docker Compose 的安装 Docker Compose 的功能 使用步骤 核心功能 Docker Compose 使用场景 Docker Compose 文件&#xff08;docker-compose.yml&#xff09; 模仿示例 文件基本结构及常见…

鸿蒙NEXT应用示例:切换图片动画

【引言】 在鸿蒙NEXT应用开发中&#xff0c;实现图片切换动画是一项常见的需求。本文将介绍如何使用鸿蒙应用框架中的组件和动画功能&#xff0c;实现不同类型的图片切换动画效果。 【环境准备】 电脑系统&#xff1a;windows 10 开发工具&#xff1a;DevEco Studio NEXT B…

【spring 】Spring Cloud Gateway 的Filter学习

介绍和使用场景 Spring Cloud Gateway 是一个基于 Spring Framework 5 和 Project Reactor 的 API 网关&#xff0c;它旨在为微服务架构提供一种简单而有效的方式来处理请求路由、过滤、限流等功能。在 Spring Cloud Gateway 中&#xff0c;Filter 扮演着非常重要的角色&#…

opencv(c++)图像的灰度转换

opencv(c)图像的灰度转换 quickopencv.h #pragma once #include <opencv2/opencv.hpp> using namespace cv; class QuickDemo { public:void colorSpace_Demo(Mat& image); };quickopencv.cpp #include "quickopencv.h"// QuickDemo类中的颜色空间演示函…

problem forward和solution backward有什么区别

Note: 在具体研究中&#xff0c;problem forward是先提出问题&#xff0c;然后围绕着科学问题设计出完美的解决方案&#xff1b;而solution backward是先盘算自己有哪些技术&#xff0c;有哪些解决方案&#xff0c;反过来去寻找和定义问题。

C++构造函数详解

构造函数详解&#xff1a;C 中对象初始化与构造函数的使用 在 C 中&#xff0c;构造函数是一种特殊的成员函数&#xff0c;它在创建对象时自动调用&#xff0c;用来初始化对象的状态。构造函数帮助我们确保每个对象在被创建时就处于一个有效的状态&#xff0c;并且在不传递任何…

使用WebSocket技术实现Web应用中的实时数据更新

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用WebSocket技术实现Web应用中的实时数据更新 使用WebSocket技术实现Web应用中的实时数据更新 使用WebSocket技术实现Web应用中…