Давным-давно был вид бумаги по этим направлениям: Говард Хиннант : N2199 . Самый первый пример демонстрирует конкретную проблему, которую вы пытаетесь решить:
Функция не может использоваться слева от назначения:
int x = 1;
int y = 2;
std::min(x, y) = 3; // x == 3 desired, currently compile time error
Далее он приводит в качестве примеров часто встречающуюся справочную проблему, типы смешивания и полезность для типов только для перемещения, а также предлагает новые версии min
и max
, которые решают все эти проблемы - он включает в себя очень тщательную реализацию в нижней части (которая слишком длинна, чтобы вставить здесь). Реализация minmax()
, основанная на этом, должна быть довольно простой:
template <class T, class U,
class R = typename min_max_return<T&&, U&&>::type>
inline
std::pair<R, R>
minmax(T&& a, U&& b)
{
if (b < a)
return {std::forward<U>(b), std::forward<T>(a)};
return {std::forward<T>(a), std::forward<U>(b)};
}
Бумага была отклонена в то время. Возможно, это может вернуться, хотя.
Приятно возвращать изменчивые ссылки, но возможность избежать висячих ссылок еще приятнее. Анонимно цитирую пример, который я недавно видел:
template<typename T> T sign(T);
template <typename T>
inline auto frob(T x, T y) -> decltype(std::max(sign(x - y), T(0))) {
return std::max(sign(x - y), T(0));
}
Эта функция имеет неопределенное поведение для всех входов (самое узкое
договор возможен?).
Обратите внимание, что ваша реализация common
имеет эту проблему. Эти случаи:
template<class T> struct common<T, T&>{using type = T const&;};
template<class T> struct common<T&, T>{using type = T const&;};
template<class T> struct common<T const&, T>{using type = T const&;};
template<class T> struct common<T, T const&>{using type = T const&;};
все болтаться. Что это значит, если у меня есть:
int i = 4;
auto result = your_minmax(i, 5);
result
- это pair<int const&, int const&>
, один из которых является ссылкой на i
, а другой - болтается. Все эти случаи должны сделать using type = T;
, чтобы быть в безопасности.