6
\$\开始组\$

我一直在挑战自己,要找到一种方法,轻松地对一系列对象执行操作。这样做是为了防止复制列表。我想出了以下几点,我觉得很优雅。但我真的不喜欢这里的指针。我也想使用智能指针,但不要使用RTTI。

在待办事项列表中,在第一个操作之后,它应该返回一个不同的类,因此您只能执行更多的操作。因此,在第一次操作后不可能再进行过滤。

你怎么认为?这样的东西用起来好吗?(当然,这是一个简化版。真实的类和条件更复杂。)

#包括<iostream>#包含<内存>#包括<功能>#包含<矢量>结构人员{std::string名称;int年龄;};类PersonActions{std::function<void(Person*)>actions=[](Person*设备){};//默认为No-op公众:void Append(std::function操作){auto-oldAction=动作;actions=[oldAction,action](个人*设备){oldAction(设备);动作(装置);};}void执行(个人*设备){动作(装置);}};模板<类型名T>类PersonActionsBuilder{受保护的:PersonActions动作;公众:执行自定义(std::function<void(Person*)>action)(&E){行动。追加(动作);return*((T*)this);}T&AppendName(标准::字符串值){行动。附加([值](个人*设备){设备->Name.append(value);});返回*((T*)this);}打印(&P){行动。附加([](个人*设备){标准::cout<<“-名称:”<<设备->名称<<std::endl;标准::cout<<“-年龄:”<<设备->年龄<<std::endl;});return*((T*)this);}};类PersonQuery{std::function<bool(Person*)>谓词=[](Person*device){return true;};//默认情况下始终为true公众:void Append(std::function<bool(Person*)>newPredicate){auto-oldPredicate=this->谓词;this->谓词=[oldPredicate,newPredicate](Person*设备){return oldPredicate(device)&&newPredicate[device];};}bool Match(个人*设备){返回谓词(设备);}};模板<类型名T>类PersonQueryBuilder{受保护的:PersonQuery查询;公众:T&WhereCustom(std::函数<bool(Person*)>谓词){查询。追加(谓词);return*((T*)this);}T&WhereAge(int value,std::function<bool(int,int)>comparator=std::equal_to<bool>()){查询。附加([值,比较器](Person*设备){返回比较器(设备->年龄,值);});return*((T*)this);}};类PersonExecutor{公众:void Execute(PersonActions和actions,PersonQuery和query,std::vector<Person*>&devices){for(自动设备:设备){if(query.Match(设备)){行动。执行(设备);}}}};类PersonExecutableQuery:公共PersonQueryBuilder{std::vector<Person*>&devices;公众:PersonExecutableQuery(std::vector<Person*>和设备):设备(设备){}无效执行(){个人执行人执行人;执行人。执行(操作、查询、设备);}};整型main(){std::vector<Person*>个人;persons.push_back(新人物{“John Doe”,30});persons.push_back(新人物{“Jane Smith”,25});persons.push_back(新人物{“Alice Johnson”,22});persons.push_back(新用户{“Bob Brown”,45});persons.push_back(新人物{“Charlie Davis”,28});人员可执行查询(人).WhereAge(30,标准::greater_equal<int>()).AppendName(“是”).执行();PersonExecutableQuery(人).WhereAge(30,标准::less<int>()).AppendName(“无”).Execute()执行;PersonExecutableQuery(人).WhereCustom([](人*人){return person->Name.ends_with(“是”);}).打印().执行();}
\$\端组\$

2个答案2

重置为默认值
11
\$\开始组\$

紧急救援计划

C++是一种多范式语言;它提供了多种解决问题的方法,有些方法比其他方法更简单。你已经走上了面向对象的道路,托比·斯皮特(Toby Speight)展示了如何以一种更加函数化的编程风格来实现这一点。然而,也有善良的老人命令式编程你可以使用的方式。它看起来像这样:

整型main(){标准::vector<Person>persons{{“约翰·多伊”,30},{“简·史密斯”,25},{“爱丽丝·约翰逊”,22},{“鲍勃·布朗”,45岁},{“查理·戴维斯”,28},};for(auto和person:个人)if(人员年龄>=30)人。Name+=“是”;for(auto和person:个人)如果(人员年龄<30)人。名称+=“nope”;for(auto和person:个人)if(person.Name.ends_width(“是”))标准::cout<<“-姓名:”<<人。名称<<“\n”<<“-年龄:”<<人。年龄<<“\n”;}

请注意,您不需要创建任何类,也不需要学习任何标准库范围/视图/算法,只需对于如果它也非常灵活。

\$\端组\$
4
  • 4
    \$\开始组\$ 简单易懂。托比和OP的版本很吓人。 \$\端组\$
    – 哈里斯
    评论 5月22日19:50
  • \$\开始组\$ 我知道你是从哪里来的,问题是在真实的物体上,条件更复杂。所以在这个例子中,我同意它更具可读性。但当您开始使用多个嵌套的if语句检查各种情况时。转到查询样式可能更具可读性。尽管如此,我想这也是一种偏好。我同意你的解决方案是每个人都可以阅读的! \$\端组\$ 评论 5月23日6:26
  • 1
    \$\开始组\$ 编辑为时已晚。我想当事情变得更复杂时,你总是可以制作专用的函数。尤其是在多次使用的情况下。例如,bool CheckIfPersonIs。。。。 \$\端组\$ 评论 5月23日6:34
  • \$\开始组\$ 因为我不是唯一一个在这方面工作的人,我觉得这应该是公认的答案。这对其他人来说更容易理解。 \$\端组\$ 评论 5月23日8:49
7
\$\开始组\$

该功能类似于标准视图,但使用了非常规语法,使用函数调用和Builder模式,而不是|操作员。C++程序员更习惯于这样的东西

auto under_30s=persons|std::views::filter(compare_proj(&Person::Age,std::less<>{},30))std::ranges::for_each(under_30s,append(&Person::Name,“nope”);

甚至更简单:

标准::范围::copy(个人|std::views::filter([](auto&p){return p.年龄<30;})|std::views::transform([](auto&p){p.名称+=“yep”;返回p;}),标准::ostream_iterator<Person>{std::cout,“\n”});

当标准库如此支持时,无需自己编写和维护复杂的机器!


这些铸件是未定义的行为:

return*((T*)this);

这个…建筑商<T>类不是从派生的T型,所以它们的指针之间没有转换。


为什么要用刷新输出标准::endl而不是“\n”在这里?

标准::cout<<“-名称:”<<设备->名称<<std::endl;标准::cout<<“-年龄:”<<设备->年龄<<std::endl;

为什么我们只能打印到标准输出?我们应该将目标流作为参数传递。


我们在中泄漏内存main()因为我们有一个原始的、拥有指针的向量。避免这样做;在这里,存储起来很简单物体:标准::vector<Person>persons.如果我们将此扩展并使多态基类,然后可以考虑使用标准::vector。永远不要使用原始指针来拥有资源!


在待办事项列表中,……在第一次操作后,无法再进行筛选。

为什么?对一组项目采取行动并对其中的一个子集执行进一步的行动可能是合理的。

\$\端组\$
5
  • \$\开始组\$ 啊,我很久没有用C++编程了,所以我还不知道很多功能。在这种情况下,std::views是我没有遇到过的。我同意更标准的方法会更好。我有一个问题,可以在不复制向量的情况下进行转换吗?我使用的是嵌入式设备,所以我真的需要知道在我做这些事情时发生了什么。动态内存是所有乐趣和游戏,直到你有有限的资源。(哦,我当然会使用智能指针,打印只是示例的一部分。) \$\端组\$ 评论 5月23日6:29
  • 1
    \$\开始组\$ 标准意见不要复制集合(但另一方面是访问视图元素可以在每次访问时重新计算它们,程序员负责确保元素的存储超过其通过视图的访问)。每当你看到看法以一个名字(例如标准::字符串视图),这告诉您它访问其他东西拥有的存储。 \$\端组\$ 评论 5月23日8:05
  • 1
    \$\开始组\$ 顺便说一句标准::范围::复制()我写的是将向量的内容复制到标准输出流,即打印。它不涉及在内存中制作额外的副本。 \$\端组\$ 评论 5月23日8:06
  • \$\开始组\$ 感谢您的澄清 \$\端组\$ 评论 5月23日8:40
  • \$\开始组\$ 虽然我没有把这个问题作为公认的答案,但我很感激能学到一些新东西。 \$\端组\$ 评论 5月23日8:50

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策

不是你想要的答案吗?浏览标记的其他问题问你自己的问题