Fix that Utils::sorted could modify input container

Utils::sorted had overloads for "const Container &", "Container &&", and
"const Container &&", but for _templated_ types "Container &&" does
_not_ mean "rvalue reference", it means "rvalue or lvalue reference"
(e.g. "universal" reference).

That means that for non-const lvalue references that "Container &&"
overload was used, which modifies the input container. Which is a fine
optimization for rvalue references, but is wrong for lvalue references.

Add another overload explicitly for "Container &" before the
"Container &&" overload, and add some tests.

Also fix the compiler warning that triggered the investigation:

warning: local variable 'container' will be copied despite being
returned by name [-Wreturn-std-move]
note: call 'std::move' explicitly to avoid copying

Amends 13f40f5471

Change-Id: I14461fde5fc51a8bb679fd72b886e13b18c47e7b
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Eike Ziller
2022-12-22 09:40:34 +01:00
parent 5a4092106e
commit e38d1f06bd
2 changed files with 175 additions and 18 deletions

View File

@@ -1005,7 +1005,8 @@ inline void sort(Container &container, Predicate p)
std::stable_sort(std::begin(container), std::end(container), p);
}
template <typename Container>
// const lvalue
template<typename Container>
inline Container sorted(const Container &container)
{
Container c = container;
@@ -1013,20 +1014,34 @@ inline Container sorted(const Container &container)
return c;
}
template <typename Container>
// non-const lvalue
// This is needed because otherwise the "universal" reference below is used, modifying the input
// container.
template<typename Container>
inline Container sorted(Container &container)
{
Container c = container;
sort(c);
return c;
}
// non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
template<typename Container>
inline Container sorted(Container &&container)
{
sort(container);
return container;
return std::move(container);
}
template <typename Container>
// const rvalue
template<typename Container>
inline Container sorted(const Container &&container)
{
return sorted(container);
}
template <typename Container, typename Predicate>
// const lvalue
template<typename Container, typename Predicate>
inline Container sorted(const Container &container, Predicate p)
{
Container c = container;
@@ -1034,21 +1049,34 @@ inline Container sorted(const Container &container, Predicate p)
return c;
}
template <typename Container, typename Predicate>
// non-const lvalue
// This is needed because otherwise the "universal" reference below is used, modifying the input
// container.
template<typename Container, typename Predicate>
inline Container sorted(Container &container, Predicate p)
{
Container c = container;
sort(c, p);
return c;
}
// non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
template<typename Container, typename Predicate>
inline Container sorted(Container &&container, Predicate p)
{
sort(container, p);
return container;
return std::move(container);
}
template <typename Container, typename Predicate>
// const rvalue
template<typename Container, typename Predicate>
inline Container sorted(const Container &&container, Predicate p)
{
return sorted(container, p);
}
// pointer to member
template <typename Container, typename R, typename S>
template<typename Container, typename R, typename S>
inline void sort(Container &container, R S::*member)
{
auto f = std::mem_fn(member);
@@ -1059,7 +1087,8 @@ inline void sort(Container &container, R S::*member)
});
}
template <typename Container, typename R, typename S>
// const lvalue
template<typename Container, typename R, typename S>
inline Container sorted(const Container &container, R S::*member)
{
Container c = container;
@@ -1067,21 +1096,34 @@ inline Container sorted(const Container &container, R S::*member)
return c;
}
template <typename Container, typename R, typename S>
// non-const lvalue
// This is needed because otherwise the "universal" reference below is used, modifying the input
// container.
template<typename Container, typename R, typename S>
inline Container sorted(Container &container, R S::*member)
{
Container c = container;
sort(c, member);
return c;
}
// non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
template<typename Container, typename R, typename S>
inline Container sorted(Container &&container, R S::*member)
{
sort(container, member);
return container;
return std::move(container);
}
template <typename Container, typename R, typename S>
// const rvalue
template<typename Container, typename R, typename S>
inline Container sorted(const Container &&container, R S::*member)
{
return sorted(container, member);
}
// pointer to member function
template <typename Container, typename R, typename S>
template<typename Container, typename R, typename S>
inline void sort(Container &container, R (S::*function)() const)
{
auto f = std::mem_fn(function);
@@ -1092,7 +1134,8 @@ inline void sort(Container &container, R (S::*function)() const)
});
}
template <typename Container, typename R, typename S>
// const lvalue
template<typename Container, typename R, typename S>
inline Container sorted(const Container &container, R (S::*function)() const)
{
Container c = container;
@@ -1100,14 +1143,27 @@ inline Container sorted(const Container &container, R (S::*function)() const)
return c;
}
template <typename Container, typename R, typename S>
// non-const lvalue
// This is needed because otherwise the "universal" reference below is used, modifying the input
// container.
template<typename Container, typename R, typename S>
inline Container sorted(Container &container, R (S::*function)() const)
{
Container c = container;
sort(c, function);
return c;
}
// non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
template<typename Container, typename R, typename S>
inline Container sorted(Container &&container, R (S::*function)() const)
{
sort(container, function);
return container;
return std::move(container);
}
template <typename Container, typename R, typename S>
// const rvalue
template<typename Container, typename R, typename S>
inline Container sorted(const Container &&container, R (S::*function)() const)
{
return sorted(container, function);