c++ - 有沒有一種很好的方法將std:: minmax(a,b)分配給std:: tie(a,b)?




algorithm reference (2)

std::tie(a, b) = std::minmax(a, b);

我認為這是直觀的代碼。 乾淨,易懂。 太糟糕了,它不能按預期工作,如 const& std::minmax 模板。 因此,如果值在 std::pair<const&, const&> 中交換 std::pair<const&, const&> 比一個分配將覆蓋另一個值:

auto[a, b] = std::make_pair(7, 5);

std::tie(a, b) = std::minmax(a, b);

std::cout << "a: " << a << ", b: " << b << '\n';

a:5,b:5

這裡的預期輸出是 a: 5, b: 7

我認為這很重要,因為實現將函數應用到某些範圍的轉換函數需要這些語句用於直觀的lambdas。 例如:

std::vector<int> v{ 0, 1, 0, 2, 0 };
std::vector<int> u{ 1, 0, 1, 0, 1 };

perform(v.begin(), v.end(), u.begin(), [](auto& a, auto& b){ 
    std::tie(a, b) = std::minmax(a, b);    
}); 

//v would be == {0, 0, 0, 0, 0}
//u would be == {1, 1, 1, 2, 1}

我找到的一個解決方案是顯式構造一個 std::tuple 而沒有任何引用限定符而不是 std::pair<const&, const&> 來強制執行一個副本:

std::tie(a, b) = std::tuple<int, int>(std::minmax(a, b)); 

但是這個 <int, int> 冗餘看起來相當糟糕,特別是在之前說過 auto& a, auto& b

有沒有一個很好的,簡短的方式來執行這個分配? 可能是這是錯誤的方向,只是說 if (a >= b) { std::swap(a, b); } 這將是最好的方法嗎?


您可以使用 minmax 的初始化列表:

std::tie(a, b) = std::minmax({a, b});

這會導致創建臨時對象,就像使用 一元加號一樣 ,但是它具有與缺少 一元加 運算符的類型一起使用的好處。

using namespace std::string_view_literals;

auto [a, b] = std::make_pair("foo"sv, "bar"sv);
std::tie(a, b) = std::minmax({a, b});
std::cout << "a: " << a << ", b: " << b << '\n';

輸出:

a: bar, b: foo

可能是這是錯誤的方向,只是說 if (a >= b) { std::swap(a, b); } 這將是最好的方法嗎?

if(b < a) std::swap(a, b); 我會成功 if(b < a) std::swap(a, b); 因為 Compare 1的 要求,但是,我懷疑它會更快,而且你想要完成的事情仍然很清楚。

[1] 比較[...]應用於滿足Compare類型的對象的函數調用操作的返回值,當上下文轉換為bool時,如果調用的第一個參數出現在嚴格弱的第二個參數之前,則返回true由此類型引起的排序關係,否則為false。


您可以按照以下簡潔程度強制執行此操作。

std::tie(a, b) = std::minmax(+a, +b);

std::cout << "a: " << a << ", b: " << b << '\n';

解釋:內置的一元加運算符,為了與其一元減去兄弟的對稱性, 按值 返回其操作數(它還執行通常的算術轉換,但這不適用於 int )。 這意味著它必須創建一個臨時的,即使這個臨時只是操作數的副本。 但是對於這個例子中 minmax 的使用,它就足夠了:交換引用在這裡不再分配,因為右側的引用(傳遞給 minmaxconst int& 參數)不是指那些相同的對象在左側(由 std::tie 創建的引用 tuple 內)。

輸出符合要求:

a:5,b:7





c++17