Контроль с какими ссылками `T` связывает

Размышляя о том, что можно сделать, чтобы решить std::min Одна из проблем, с которыми я сталкивался, это добавление перегрузки (фактически 3 - для каждой комбинации) для r-значений, которые будут удалены. Проблема в том, что T&& будет ссылкой на пересылку, а не ссылкой на значение.

Я хочу отделить этот вопрос от std::min конкретно и сделать его более общим. std::min может быть взят в качестве примера, зачем вам такая вещь.

Позволяет упростить и обобщить проблему:

// this has the same problem as `std::min`: if t binds to a temporary,
// and the result is assigned to `auto&`, the result is a dangled reference
template <class T>
const T& foo(const T& t)
{
  return t;
}

// incorrect attempt to prevent foo from being called with a temporary argument
// `T&&` is a forwarding reference, not an rvalue reference
template <class T>
const T& foo(T&& t) = delete;

Вопрос в том, как вы можете контролировать, к каким ссылкам относится общий параметр шаблона. T может связать? И как это может масштабироваться для нескольких аргументов (как в std::min дело)?

2 ответа

Решение

Учитывая ваш код, следующее не может скомпилировать

int i = 0;
foo(i);      // deleted function

Причина, по которой выбрана перегрузка эталонной пересылки, заключается в том, что для соответствия другой требуется const квалификация. Но если бы вы должны были написать

int const i = 0;
foo(i);      // perfectly fine

В этом случае выбирается перегрузка, принимающая значение lvalue.

Таким образом, чтобы отклонить все значения, deleteд функция должна взятьT const&&(Это то, чтоstd::ref делает, чтобы отклонить значения)

template <class T>
const T& foo(const T& t)
{
  return t;
}

template <class T>
const T& foo(T const&& t) = delete;

Живая демо

Вы можете сделать

template <typename T>
std::enable_if_t<std::is_rvalue_reference<T&&>::value>
foo(T&&) = delete;

демонстрация

Для 2 аргументов это становится:

template <typename T1, typename T2>
std::enable_if_t<
    (std::is_rvalue_reference<T1&&>::value
    || std::is_rvalue_reference<T1&&>::value)
    && std::is_same<std::decay_t<T1>, std::decay_t<T2>>::value
>
foo(T1&&, T2&&) = delete;

Преторианская версия будет такой:

template <class T> void foo(const T&&, const T&) = delete;
template <class T> void foo(const T&, const T&&) = delete;
template <class T> void foo(const T&&, const T&&) = delete;
Другие вопросы по тегам