[英]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.