【C++】STL 算法 ⑪ ( 函数适配器嵌套用法 | modulus 函数对象 - 取模运算 | std::count_if 函数原型 | std::not1 函数原型 )

2024-01-12 09:28:13 浏览数 (2)

一、函数适配器示例 - 函数适配器正常用法

1、modulus 函数对象 - 取模运算

在 <functional> 头文件 中 , 预定义了 modulus 函数对象 , 这是一个 二元函数对象 , 在该函数对象类中 , 重写了 函数调用操作符 函数 operator() , 该 预定义函数对象 代码如下 :

代码语言:javascript复制
// STRUCT TEMPLATE modulus
template <class _Ty = void>
struct modulus {
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type;
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type;
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty result_type;

    constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const {
        return _Left % _Right;
    }
};

该函数对象 定义了 模板参数 template <class _Ty = void> , _Ty 泛型的默认参数是 void , 即 如果 不指定 模板参数 , _Ty 泛型就是 void 类型 , 一般情况下使用 int 类型 进行取模运算 ;

在 modulus 函数对象 中 , 重载 函数调用操作符 函数 是最核心的函数 , 在该函数中 , 将第一个参数 const _Ty& _Left 与 第二个参数 const _Ty& _Right 进行取模运算 , 返回 模运算 的结果 ;

代码示例 :

代码语言:javascript复制
#include "iostream"
using namespace std;
#include "functional"

int main() {

	// 创建函数对象
	modulus<int> mod;

	// 调用函数对象
	int result = mod(5, 2);

	// 打印执行结果
	cout << "result = " << result << endl;


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
	return 0;
};

执行结果 :

2、std::count_if 函数原型

std::count_if 函数 是 C 标准库算法 , 该 函数 的作用是 计算范围内满足特定条件的元素的数量 , 该函数 接受 一个迭代器范围 和 谓词函数 ;

注意 : 迭代器范围 的 起始迭代器 ~ 终止迭代器 是一个 前闭后开区间

std::count_if 算法的 函数原型 如下 :

代码语言:javascript复制
// FUNCTION TEMPLATE count_if
template <class _InIt, class _Pr>
_NODISCARD _Iter_diff_t<_InIt> count_if(_InIt _First, _InIt _Last, _Pr _Pred) { // count elements satisfying _Pred
    _Adl_verify_range(_First, _Last);
    auto _UFirst               = _Get_unwrapped(_First);
    const auto _ULast          = _Get_unwrapped(_Last);
    _Iter_diff_t<_InIt> _Count = 0;
    for (; _UFirst != _ULast;   _UFirst) {
        if (_Pred(*_UFirst)) {
              _Count;
        }
    }

    return _Count;
}
  • _InIt _First 参数 : 迭代器范围的 起始迭代器 , 包括本迭代器指向的元素 ;
  • _InIt _Last 参数 : 迭代器范围的 终止迭代器 , 不包括本迭代器指向的元素 ;
  • _Pr _Pred 参数 : 谓词函数 ;

3、代码示例 - 使用 函数适配器 绑定函数对象参数

在下面的代码中 , 将 myVector 单端数组 容器 中的元素 设置给 modulus 函数对象的 第一个参数 , 将 equal_num 变量设置为 该 modulus 函数对象的 第二个参数 , 然后依次遍历 myVector 单端数组 容器 将每个元素 与 equal_num 进行取模运算 ;

代码语言:javascript复制
	// 计算 vector 容器中 , 值为 2 的个数
	int equal_num = 2;
	// 取模运算 , 模 2 返回值 1 就是奇数 , 返回值 0 就是偶数
	int count = count_if(myVector.begin(), myVector.end(), bind2nd(modulus<int>(), 2));

代码示例 :

代码语言:javascript复制
#include "iostream"
using namespace std;
#include <vector>
#include <algorithm>
#include "functional"

int main() {

	// 创建一个 set 集合容器
	vector<int> myVector;

	// 向容器中插入元素
	myVector.push_back(9);
	myVector.push_back(5);
	myVector.push_back(2);
	myVector.push_back(7);
	myVector.push_back(2);

	// 向 foreach 循环中传入 Lambda 表达式
	for_each(myVector.begin(), myVector.end(), [](int a) {
		std::cout << a << " ";
		});
	cout << endl;

	// 计算 vector 容器中 , 值为 2 的个数
	int equal_num = 2;
	// 取模运算 , 模 2 返回值 1 就是奇数 , 返回值 0 就是偶数
	int count = count_if(myVector.begin(), myVector.end(), bind2nd(modulus<int>(), 2));
	cout << "值奇数元素个数 : " << count << endl;


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
	return 0;
};

二、函数适配器示例 - 函数适配器嵌套用法


1、std::not1 函数原型

std::not1 是 预定义的 函数适配器 函数 , 该 函数 接收一个 一员函数对象 , 返回新的 一元函数对象 , 返回的 一元函数对象 是对输入的 一元函数对象 的 结果 进行 逻辑非 运算 ;

std::not1 函数原型如下 :

代码语言:javascript复制
template <class UnaryPredicate>  
unary_negate<UnaryPredicate> not1(UnaryPredicate pred);
  • UnaryPredicate pred 参数 : 一元谓词 , 也就是 接受单个参数 并返回布尔值的可调用对象 ;
  • unary_negate<UnaryPredicate> 类型返回值 : 返回值 是 封装了 UnaryPredicate 并提供了一个 operator() 成员函数 的 一元谓词 , 该函数对 UnaryPredicate 的结果取反 ;

std::not1 可以 与 std::bind1st 或 std::bind2nd 嵌套使用 , 创建更复杂的谓词 ;

2、代码示例 - 函数适配器嵌套用法

核心代码如下 :

代码语言:javascript复制
	// 计算 vector 容器中 , 值为 2 的个数
	int equal_num = 2;
	// 取模运算 , 模 2 返回值 1 就是奇数 , 返回值 0 就是偶数
	// not1 将其取反 也就是获取的是 非奇数 个数
	int count = count_if(myVector.begin(), myVector.end(), not1(bind2nd(modulus<int>(), 2)));

下面的代码中 , modulus 是一个二元函数对象 , 返回 0 或 1 可以当做 二元谓词 ;

bind2nd(modulus<int>(), 2) 将 二元谓词 中的 第二个元素进行了绑定 , 只需要接收一个参数 , 变成了 一元谓词 ;

not1(bind2nd(modulus<int>(), 2)) 将 上述 一元谓词 取反 , 得到一个新的一元谓词 ;

代码示例 :

代码语言:javascript复制
#include "iostream"
using namespace std;
#include <vector>
#include <algorithm>
#include "functional"

int main() {

	// 创建一个 set 集合容器
	vector<int> myVector;

	// 向容器中插入元素
	myVector.push_back(9);
	myVector.push_back(5);
	myVector.push_back(2);
	myVector.push_back(7);
	myVector.push_back(2);

	// 向 foreach 循环中传入 Lambda 表达式
	for_each(myVector.begin(), myVector.end(), [](int a) {
		std::cout << a << " ";
		});
	cout << endl;

	// 计算 vector 容器中 , 值为 2 的个数
	int equal_num = 2;
	// 取模运算 , 模 2 返回值 1 就是奇数 , 返回值 0 就是偶数
	// not1 将其取反 也就是获取的是 非奇数 个数
	int count = count_if(myVector.begin(), myVector.end(), not1(bind2nd(modulus<int>(), 2)));
	cout << "偶数元素个数 : " << count << endl;


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
	return 0;
};

执行结果 :

代码语言:javascript复制
9 5 2 7 2
偶数元素个数 : 2
请按任意键继续. . .

0 人点赞