use*_*670 8 c++ algorithm pointer-to-member c++-standard-library c++17
标准库中的许多算法接受带有签名的一元谓词,bool (Type & item)因此直接提供指向非静态成员函数的指针不起作用.考虑到通过调用替换operator ()对谓词的直接调用似乎可以解除这种限制,这似乎是相当严格的std::invoke.也许提出的方法有一些我忽略的缺点?
注意:此问题中引用的非静态成员函数应该与常规函数谓词不同,只是因为项引用作为隐式参数而不是显式参数传递.
示例代码(在线编译器):
#include <array>
#include <algorithm>
#include <iostream>
#include <functional>
#include <cassert>
template<typename TForwardIterator, typename TPredicate> TForwardIterator
vtt_find_if
(
const TForwardIterator p_items_begin
, const TForwardIterator p_items_end
, TPredicate && predicate
)
{
TForwardIterator p_item(p_items_begin);
// while((p_items_end != p_item) && (!predicate(*p_item)))
while((p_items_end != p_item) && (!::std::invoke(predicate, *p_item)))
{
++p_item;
}
return(p_item);
}
class t_Ticket
{
private: int m_number;
public:
t_Ticket(const int number): m_number(number) {}
public: bool
Is_Lucky(void) const {return(8 == m_number);}
};
int main()
{
::std::array<t_Ticket, 10> tickets{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// using standard library
auto p_ticket1(::std::find_if(tickets.begin(), tickets.end(), [](const t_Ticket & ticket) {return(ticket.Is_Lucky());}));
// still works
auto p_ticket2(vtt_find_if(tickets.begin(), tickets.end(), [](const t_Ticket & ticket) {return(ticket.Is_Lucky());}));
// same thing, but shorter and not sufferring from potential lambda code duplication
auto p_ticket3(vtt_find_if(tickets.begin(), tickets.end(), &t_Ticket::Is_Lucky));
// using standard library like this won't compile
//auto p_ticket4(::std::find_if(tickets.begin(), tickets.end(), &t_Ticket::Is_Lucky));
assert(p_ticket1 == p_ticket2);
assert(p_ticket2 == p_ticket3);
return(0);
}
Run Code Online (Sandbox Code Playgroud)
首先,假设问题是:
为什么算法不能将泛型
Callable作为谓词/动作?
我可以想到多种原因:
这个Callable概念是在C++ 11中引入的 - 前C++ 11算法并没有考虑到它的设计.
接受任何一个Callable都需要扩展概念,例如Predicate允许算法有条件地为成员函数指针添加一个额外的参数.这可能导致不必要的复杂性,可以通过简单地将界面限制为FunctionObject并强制用户进行"绑定" 来避免这种复杂性.
考虑到现在还存在执行策略重载,这会显着增加过载量.或者,它可以使每个算法成为可变参数模板,其中参数包可以包含零个或一个参数(如果*this需要为a提供Callable).
std::invoke不是constexpr.使用它可能会阻止算法constexpr在将来被标记.
如果您指的是特定情况:
该算法在均匀范围内运行T.
谓词T在范围的每个类型元素上执行.
T 有一个可以用作谓词的成员函数.
然后,我仍然可以想到一些可能的原因:
std::invoke仍然没有constexpr.我们可以避免使用std::invokefor .*,但是我们需要为每个算法提供两个单独的实现.
如果成员函数是一个template或一个重载集,那么这将无法编译并使初学者感到困惑.通用lambda没有这个问题.
它会使算法的要求复杂化 - 需要对成员函数的类型/签名进行某种限制,以确保它在范围内可用T.
或许......它还没有提出.如果您仍然认为在我提出原因之后拥有它是有价值的,那么您可以从这里开始学习如何撰写提案:https://isocpp.org/std/submit-a-proposal
| 归档时间: |
|
| 查看次数: |
398 次 |
| 最近记录: |