当前位置: 首页 > news >正文

函数指针在C++遍历函数中的写法和应用(直接在函数中定义函数指针)。

例子,在Qt中,有一个右键菜单,我想把菜单中的节点改为章节。

这里要用到遍历函数:

void traverseMenu(QMenu* menu, bool(*f)(QAction* a))
{
    assert(menu && f);

    // 遍历当前菜单的所有动作(QAction)
    for (QAction* action : menu->actions()) {
        if (action->menu()) { // 如果是子菜单 
            traverseMenu(action->menu(),f); // 递归遍历
        }
        if (f(action)) return;
    }
}
 

然后traverseMenu用法如下:

qt.traverseMenu(&m, [](QAction* a)->bool {

	a->setText(a->text().replace("节点", "章节"));

    return false; //遍历全部
});

效果如下:

如果你要把 “彻底删除” 改为“CSDN”,可以这样:

qt.traverseMenu(&m, [](QAction* a)->bool {

	if (a->text() == "彻底删除") {

		a->setText("csdn");
		return true;  //结束遍历
	}
	return false;
});

现在重点来了,现在的每一种数据结构,都支持  for( auto& item: container),你可以把traverseMenu写成模板函数。

template<class T, class fun>
void traverse(const T& container,const fun& f) {
 
    for (auto& item : container) {
         if (f(item)) return;
    }
}

下面把“csdn” 改为 “彻底删除” 。

qt.traverse(m.actions(), [](QAction* a)->bool {

	if (a->text() == "csdn") {

		a->setText("彻底删除");
		return true;
	}
	return false;
});

但是如果子菜单中还有子菜单,则要自己检查Action中还有没有子菜单,这是模板函数的及限性。

if (action->menu()) {


}

但是模板函数的通用性很强:

template<class T, class fun>
const T& traverse(T& container, const fun& f) {

    for (auto& item : container) {
        if (f(item)) return container;
    }

	return container;
}

int main(int argc, char* argv[])
{
	QApplication a(argc, argv);  //注意,这里是QApplication
 
	 
	std::vector<int> v = { 1,3,3,5,7 };

	std::list<std::string> s = { "abc","345","678","abc"};

	traverse(v, [](int& item)->bool {
		if (item == 3) {  //修改一个
			item = 2;
			return true;
		}
		return false;
	});

	traverse(s, [](std::string& item)->bool { 

			if (item == "abc")  //修改所有
				item = "123";

			return false;  
		}
	);

	for (auto& item : v) {
		std::cout << item;
		std::cout << "\t";
	}

	std::cout << "\n";

	for (auto& item : s) {
		std::cout << item;
		std::cout << "\t";
	}

	return a.exec();
	 
}

上次说过,这只是简单的遍历,还不如直接在代码中写一个循

环,但是在复杂的数据结构中,如树,图,你可能会发觉提早写

一个遍历函数很有用。

另:你可能要准备两个版本的traverse。

/// <summary>
/// 遍历,可修改原值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="fun"></typeparam>
/// <param name="container"></param>
/// <param name="f"></param>
/// <returns></returns>
/// 创建时间: 2025-03-30      最后一次修改时间:2025-03-30
template<class T, class fun>
T& traverse(T& container,const fun& f) {
 
   for (auto& item : container) {
        if (f(item)) return container;
   }

   return container;
}

/// <summary>
/// 遍历,不可修改源值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="fun"></typeparam>
/// <param name="container"></param>
/// <param name="f"></param>
/// <returns></returns>
/// 创建时间: 2025-03-30      最后一次修改时间:2025-03-30
template<class T, class fun>
const T& traverse(const T& container, const fun& f) {

    for (const auto& item : container) {
        if (f(item)) return container;
    }

    return container;
}

在模板函数中为什么不用函数指针,例如:

template<class T, class value_type>
const T& traverse(T& container, bool (*f)(value_type item)) { ... }

因为使用函数指针有两个缺点:

(1)

  • value_type 需要正确推导为 QAction*,但编译器可能无法准确推断(特别是当 m.actions() 返回的类型较复杂时)。

  • 即使推导正确,某些编译器可能对 模板 + 函数指针 + lambda 隐式转换 的支持不够完善,导致报错。

(2)

    traverse 函数的第二个参数 是一个 函数指针,其类型是: 

        bool (*f)(value_type item)

               这意味着它只能接受 普通函数 或 无捕获的 lambda即 [] 内没有变量的 lambda)。

                除非你用 std::function,上次说过原因,下面A,B 两篇文章解释过

                A

                Qt控件中函数指针使用的最终版本,使用std::function函数指针使用

                B接上一主题,在Qt中,用信号代替函数指针,最终目标都是能直接使用lambda表达式,效果一样。-CSDN博客

   


 

               

相关文章:

  • 有出国做飞机求同行的网站关键词优化推广排名软件
  • 山东网站建设公司哪家专业免费营销软件网站
  • 福田做网站公司怎么选十大免费cms建站系统介绍
  • 成都 企业网站建设世界足球世界排名
  • 福州设计网站建设seo搜索铺文章
  • 网站建设 软件开发搜狗提交入口网址
  • Python调用手机摄像头检测火焰烟雾的三种方法
  • python定时调度升级
  • 使用 Ansys Discovery 可视化液体池中的水流
  • ES拼音分词自动补全实现
  • LLMs之PE:《Tracing the thoughts of a large language model》翻译与解读
  • 单例模式解析
  • 畅享电脑流畅运行:深度卸载、智能监视与空间释放
  • JS绘制叠加图片
  • 04_SQL概述及DDL
  • docker镜像拉取失败
  • Foldseek快速蛋白质结构比对
  • 计算机组成原理笔记(八)——2.4十进制和数串的表示
  • D4RL库的安装历程及成功经验
  • Golang并发编程:Data Race检测与解决方案
  • Qt非阻塞延时实现
  • 基于 GEE 的区域降水数据可视化:从数据处理到等值线绘制
  • java连接opcua
  • 关于单片机IAP升级的那点事儿|智能设置中断向量表
  • PyTorch单机多卡训练(DataParallel)
  • 人工智能通识速览一(神经网络)(编辑中)