[英]Why std::overload instead of concepts/constexpr if in std::visit?
我可能對std :: overloaded提案和/或概念有些困惑,但是根據目前對這兩者的理解,我有以下問題:
為什么C ++ 20不只是概念化/如果對std :: visit進行constexprify,所以它知道基於傳遞給它的參數類型該怎么做。
例如為什么我們不能有std :: visit根據傳遞的參數的概念來修改它的行為(它所需要的只是函數在前,變量在后)。
因此,例如,這兩個visit
接受3個參數,但邏輯不同。
std::variant<int, double> v1=4.7;
std::variant<bool, std::string> v2=false;
// calls lambda that is a better fit(double one)
std::visit([](int& a){std::cout<< sizeof (a);},[](double& a){std::cout << a;} , v1);
// calls lambda on variant v1 and then variant v2
std::visit([](auto& a){}, v1, v2);
我認為這將是一個非常糟糕的主意。
從概念上講,現在visit
是一項簡單的功能。 它這樣做:
template <typename F, typename... Variants>
decltype(auto) visit(F f, Variants... vs) {
return f(std::get<vs.index()>(vs)...);
}
當然, vs.index()
不是一個常量表達式,所以您不能只是這樣做,而是需要整個復雜的實現才能使它起作用。 但是重點是- visit
一堆變量只會在每個變量的當前替代項上調用f
。 這很容易推理。
讓通用算法根據傳遞的類型在語義上做不同的事情是一個非常糟糕的主意。 這意味着您不能真正考慮代碼的正確性-因為它基本上可以做任何事情。 OP中的最后一個例子就是一個很好的例子:
std::visit([](auto&){}, v1, v2); // #1
std::visit([](auto&, auto&){}, v1, v2); // #2
今天, #1
(OP示例)無法編譯,因為您正在將一元函數傳遞給二進制訪問者。 這是一件好事。 但與建議,都將編譯和瘋狂做不同的事情。 一個將依次訪問每個變體,另一個將一起訪問每個變體。
用戶意圖是什么? 也許#1
是一個錯誤,用戶要么忘記了一個論點,要么提供了一個訪問者,該訪問者在大多數(但不是全部)情況下都充當二進制訪問者,但在所有情況下都充當一元訪問者?
OP中的另一個示例不太糟糕,它具有:
visit(f1, f2, f3, v1, v2, v3)
表示對三個組合功能進行三元訪問,而不是對一個功能進行三元訪問:
visit(overload(f1, f2, f3), v1, v2, v3)
但這將以非常小的增益實現(用戶只需將功能包裝在自己的右邊?),實施起來將非常復雜,並且您必須開始提出類似的問題:如果您擁有一個可調用的variant
呢?
如果您要使用其他語法,那么我已經看到了一些代碼示例,其中人們可以通過語法來實現訪問,例如:
visit2(v1, v2, v3)(f1, f2, f3)
這非常容易實現:
template <typename... Variants>
auto visit2(Variants&&... variants) {
return [&](auto&&... fs) -> decltype(auto) {
return std::visit(overload(FWD(fs)...), FWD(variants)...);
};
}
並具有將變量放在首位而不必編寫overload
的好處。 也許就足夠了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.