2

Не задумываясь о том, что можно сделать для решения проблемы std::mindangling reference problem, я подумал, что я должен был добавить перегрузку (фактически 3 - для каждой комбинации) для rvalues, которые будут удалены. Проблема в том, что T&& будет ссылкой на пересылку, а не ссылкой на rvalue.Контроль над тем, какие ссылки `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)?

ответ

3

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

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

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

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

В этом случае перегрузки принимая lvalue reference is selected.

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

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

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

Live demo

+0

Очень хороший пример с 'std :: ref' – bolov

+0

Вы видите более простой способ сделать эту работу для нескольких параметров, кроме объявления каждой возможной комбинации http://ideone.com/AJgqV8? – bolov

+0

@bolov Нет, я не вижу другого пути. Похоже, это либо ужасное выражение 'enable_if', либо несколько удаленных перегрузок. Ни один из них не является особенно привлекательным. – Praetorian

4

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

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

Demo

Для 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; 
+0

так просто, и все же я пропустил , У меня все получилось сложнее в голове. – bolov

+0

@bolov: Вы должны делать 'foo (T1 &&, T2 &&)'. иначе они должны быть выведены как один и тот же тип. – Jarod42