C++ C++;std::mem_fn和std::反过来绑定

C++ C++;std::mem_fn和std::反过来绑定,c++,algorithm,member-function-pointers,C++,Algorithm,Member Function Pointers,所以我一直在研究使用抽象算法来重用代码中重复出现的模式。具体地说,我想确定节点数组中具有最高“分数”的元素的值,该值由对复杂评分成员函数的求值确定 在我提出(C++17)之后 和我的节点数组: std::array<Node, 100000> nodes; 但是现在我想对Score2重复这一点,其中输入取决于一些局部变量。。。当然我可以写一些lambda函数。。。但是我们有std::bind,对吗?我知道你可以对一个成员函数进行cal绑定,比如 std::bind(this, st

所以我一直在研究使用抽象算法来重用代码中重复出现的模式。具体地说,我想确定节点数组中具有最高“分数”的元素的值,该值由对复杂评分成员函数的求值确定

在我提出(C++17)之后

和我的节点数组:

std::array<Node, 100000> nodes;

但是现在我想对Score2重复这一点,其中输入取决于一些局部变量。。。当然我可以写一些lambda函数。。。但是我们有
std::bind
,对吗?我知道你可以对一个成员函数进行cal绑定,比如

std::bind(this, std::mem_fn(Node::Score1));
但我想要的是另一种方式。这不管用

auto const& Node = *std::max_eval_element(std::cbegin(nodes), std::cend(nodes), std::bind(std::mem_fn(&Node::Score2), 1.0));
我试过另一种方法,但也不起作用

auto const& Node = *std::max_eval_element(std::cbegin(nodes), std::cend(nodes), std::mem_fn(std::bind(&Node::Score2), 1.0));
我知道为什么这不起作用。。。成员函数需要对象指针作为(隐藏的)第一个参数。但这意味着我们缺少了类似于
std::bind\u mem\u fn
之类的东西。。。过去我们有
std::bind2nd
,但它在C++17中被删除了

再说一遍:当然我可以使用lambda,但是考虑到存在像
std:mem\u fn
std::bind
这样的东西,抽象算法是一件好事

我是否遗漏了什么,或者这只是标准中遗漏了什么?

问题在于调用
std::bind(&Node::Score2)
。它缺少传递到
Score2
的参数。你想要:

std::bind(&Node::Score2, std::placeholders::_1, 1.0)
这不是指向成员的指针,因此它不是指向
std::mem\u fn

或者,您可以使用lambda

[](const auto & node) { return node.Score2(1.0); }

我得出结论,lambda的优化比std::mem_fn更好

以这个代码为例:

#include <iostream>
#include <array>
#include <functional>

class Node {
private:
    double val;
public:
    Node(double val) noexcept : val(val) {}

    [[nodiscard]] auto Score() const noexcept {
        return 10.0 / val;
    }
};

template <typename FwdIt, typename Eval, typename Pred = std::less<>>
constexpr FwdIt max_eval_element(FwdIt first, FwdIt last, Eval eval, Pred pred = Pred()) {
    FwdIt found = first;
    if (first != last) {
        auto best = eval(*found);
        while (++first != last) {
            if (auto const thisVal = eval(*first);
                pred(best, thisVal)) {
                found = first;
                best = thisVal;
            }
        }
    }
    return found;
}

int main()
{
    std::array<Node, 10> nodes{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    auto nodeIt1 = max_eval_element(std::cbegin(nodes), std::cend(nodes), std::mem_fn(&Node::Score));
    std::cout << "dist1 " << std::distance(std::cbegin(nodes), nodeIt1) << std::endl;

    auto nodeIt2 = max_eval_element(std::cbegin(nodes), std::cend(nodes), [](Node const& node) { return node.Score(); });
    std::cout << "dist2 " << std::distance(std::cbegin(nodes), nodeIt2) << std::endl;
}
,而lambda是内联的

69 movsd   xmm1, QWORD PTR .LC0[rip]
70 divsd   xmm1, QWORD PTR [rax]

“我可以编写一些lambda函数……但是我们有std::bind,对吗?”->这是另一种方式;您应该更喜欢lambda's,因为它们提出的问题比使用
std::bind
要少得多。没有什么可以阻止您不重复使用lambda's。对于初学者来说,您不必将它们声明为内联的。而且编译器会更好地优化lambda……这不是
std::placeholder
的作用吗
std::bind(std::mem_fn(&Node::Score2),std::占位符::_1,1.0)
lambda比
std::bind
更加灵活和习惯。它们相当于(或多或少地)函子对象的语法糖分,因此编译器可以保证在指尖就有它可以用于优化的所有信息<代码>标准::绑定来自lamdba存在之前的时代,并且已经被它们取代。不!所以
std::mem\u fn(&someFn)
实际上等于
std::bind(&someFn,std::占位符::_1)
?哈哈,真的。。。那就不平等了。。。这将是一个等待发生的意外事实,不,它类似于std::bind(&SomeClass::someFn,std::占位符::_1,…std::占位符::_N),也就是说,它总是有正确数量的参数
mem_fn
调用通过函数指针,这是众所周知的难以优化的。lambda使用直接函数调用,这对于任何园艺品种优化器来说都是小菜一碟。。。显然,这方面的洞察和解释足以让您在堆栈溢出上获得-1。“和蔼可亲”怎么了?
[](const auto & node) { return node.Score2(1.0); }
#include <iostream>
#include <array>
#include <functional>

class Node {
private:
    double val;
public:
    Node(double val) noexcept : val(val) {}

    [[nodiscard]] auto Score() const noexcept {
        return 10.0 / val;
    }
};

template <typename FwdIt, typename Eval, typename Pred = std::less<>>
constexpr FwdIt max_eval_element(FwdIt first, FwdIt last, Eval eval, Pred pred = Pred()) {
    FwdIt found = first;
    if (first != last) {
        auto best = eval(*found);
        while (++first != last) {
            if (auto const thisVal = eval(*first);
                pred(best, thisVal)) {
                found = first;
                best = thisVal;
            }
        }
    }
    return found;
}

int main()
{
    std::array<Node, 10> nodes{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    auto nodeIt1 = max_eval_element(std::cbegin(nodes), std::cend(nodes), std::mem_fn(&Node::Score));
    std::cout << "dist1 " << std::distance(std::cbegin(nodes), nodeIt1) << std::endl;

    auto nodeIt2 = max_eval_element(std::cbegin(nodes), std::cend(nodes), [](Node const& node) { return node.Score(); });
    std::cout << "dist2 " << std::distance(std::cbegin(nodes), nodeIt2) << std::endl;
}
42 movsd   QWORD PTR [rsp+8], xmm1
43 call    Node::Score() const
44 movsd   xmm1, QWORD PTR [rsp+8]
69 movsd   xmm1, QWORD PTR .LC0[rip]
70 divsd   xmm1, QWORD PTR [rax]