簡體   English   中英

C++ std::mem_fn 和 std::bind 反過來

[英]C++ std::mem_fn and std::bind the other way around

所以我一直在研究使用抽象算法在我的代碼中重用重復出現的模式。 具體來說,我想確定節點數組中具有最高“分數”的元素,該元素是通過對復雜評分成員 function 的評估來確定的。

經過一些幫助,我想出了(C++ 17)

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;
}

所以考慮我的節點 class:

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

    [[nodiscard]] auto Score1() const noexcept {
        return std::sqrt(std::log(10.0 / val));
    }

    [[nodiscard]] auto Score2(double other) const noexcept {
        return std::sqrt(std::log(other / val));
    }
};

和我的節點數組:

std::array<Node, 100000> nodes;

我可以打電話

auto const& Node = *std::max_eval_element(std::cbegin(nodes), std::cend(nodes), std::mem_fn(&Node::Score1));

但現在我想對Score2重復這個,其中輸入取決於一些局部變量......當然我可以寫一些 lambda function ......但我們有std::bind ,對吧? 我知道你可以在成員 function 上綁定

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));

我知道為什么這不起作用...成員 function 需要 object 指針作為(隱藏的)第一個參數。 但這意味着我們缺少諸如std::bind_mem_fn之類的東西......我們過去有std::bind2nd ,但它已在 C++17 中刪除......

再說一遍:當然我可以使用 lambda,但是考慮到std:mem_fnstd::bind之類的東西存在,抽象算法是一件好事……

我是否遺漏了什么,或者這只是標准中遺漏的?

調用std::bind(&Node::Score2)是問題所在。 它缺少 arguments 傳遞給Score2 你要:

std::bind(&Node::Score2, std::placeholders::_1, 1.0)

這不是指向成員的指針,因此它不是std::mem_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;
}

如果您查看已編譯的程序集(例如在 GodBolt 上,使用 -O2 ),則 std:mem_fn 結果是 function 調用

42 movsd   QWORD PTR [rsp+8], xmm1
43 call    Node::Score() const
44 movsd   xmm1, QWORD PTR [rsp+8]

,而 lambda 是內聯的

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM