簡體   English   中英

std :: invoke和std :: apply有什么區別?

[英]What is the difference between std::invoke and std::apply?

它們都被用作調用函數,成員函數和通常可調用的任何東西的通用方法。 從cppreference我看到的唯一真正的區別是,在std::invoke ,函數參數(無論它們是多少)都forward給函數,而在std::apply ,參數作為tuple傳遞。 這真的是唯一的區別嗎? 為什么他們會創建一個單獨的函數來處理tuple

這真的是唯一的區別嗎? 為什么他們會創建一個單獨的函數來處理元組?

因為你真的需要兩個選項,因為他們做了不同的事情。 考慮:

int f(int, int);
int g(tuple<int, int>);

tuple<int, int> tup(1, 2);

invoke(f, 1, 2); // calls f(1, 2)
invoke(g, tup);  // calls g(tup)
apply(f, tup);   // also calls f(1, 2)

考慮特別是間差invoke(g, tup)解壓tuple ,和apply(f, tup) ,這確實。 你有時需要兩者,需要以某種方式表達。


你是對的, 通常這些是非常密切相關的操作。 實際上,Matt Calabrese正在編寫一個名為Argot的庫,它結合了兩個操作,你不是通過你調用的函數來區分它們,而是通過如何裝飾參數來區分它們:

call(f, 1, 2);         // f(1,2)
call(g, tup);          // g(tup)
call(f, unpack(tup));  // f(1, 2), similar to python's f(*tup)

你使用std::apply因為:

1:實現apply ,即使你有權訪問std::invoke也是一件很痛苦的事。 將元組轉換為參數包並非易事。 apply的實現看起來像這樣(來自cppref):

namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
{
    return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}
}  // namespace detail

template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
    return detail::apply_impl(
        std::forward<F>(f), std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}

當然,這不是世界上最難編寫的代碼,但它也不是一件容易的事。 特別是如果你沒有index_sequence元編程技巧。

2:因為通過解包tuple的元素來調用函數是非常有用的。 它支持的基本操作是能夠打包一組參數,傳遞該集合,然后使用這些參數調用函數。 我們在技術上已經能夠使用單個參數(通過傳遞值)來執行此操作,但通過apply ,您可以使用多個參數執行此操作。

它還允許您執行元編程技巧,例如以編程方式在語言之間進行編組。 您可以在這樣的系統中注冊一個函數,該函數具有函數的簽名(以及函數本身)。 該簽名用於通過元編程來編組數據。

當另一種語言調用您的函數時,元程序生成的函數遍歷參數類型列表,並根據這些類型從另一種語言中提取值。 它將它們提取出來的是什么? 某種保存值的數據結構。 而且由於元編程不能(輕松地)構建struct/class ,而是構建一個tuple (實際上,支持這樣的元編程是為什么tuple存在的80%)。

一旦構建了tuple<Params> ,就可以使用std::apply來調用該函數。 你不能真的用invoke做到這一點。

3:您不希望每個人都將參數粘貼到tuple ,以便能夠執行相當於invoke

4:你需要在invoke一個帶tuple的函數和apply解包tuple之間建立區別。 畢竟,如果你正在編寫一個模板函數來執行用戶指定的參數invoke ,那么如果用戶恰好提供了一個tuple作為參數並且你的invoke函數解壓縮它就會很糟糕。

您可以使用其他方法來區分案例,但具有不同的功能對於簡單案例來說是一個合適的解決方案。 如果你正在寫一個更廣義的apply風格的功能,要能夠解開tuple除了s到傳遞其他參數或解開多個元組到參數列表(或它們的組合),你會希望有一個特殊的super_invoke可以處理它。

但是invoke是一個簡單需要的簡單函數。 apply同樣apply

暫無
暫無

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

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