Правильный способ преобразования ссылки rvalue на временный параметр в const lvalue return в С++

Я пытаюсь реализовать метод поиска, чтобы извлечь ссылку на значение из контейнера и вернуть значение по умолчанию, если значение не найдено или имеет несовместимый тип.

template<class T> const T& get (key_type k, const T& def)
{
    const T* r = dynamic_cast<const T*> (find(k)); // suppose `find` returns a pointer to common base class or NULL if the key not found
    return r ? *r : def; 
}

эта функция работает некорректно, если def является временным объектом:

const sometype& val = find(key, sometype(someargs));

Итак, можно ли обработать этот случай, используя ссылку rvalue и каким-то образом перемещая или копируя временный объект?

template<class T> const T& get (key_type k, T&& def)
{
    const T* r = dynamic_cast<const T*> (find(k)); // suppose `find` returns a pointer to common base class or NULL if the key not found
    return r ? *r : std::move(def); // or copy? or something else?
}

T также может быть абстрактным базовым классом. И, пожалуйста, я бы предпочел безбустовое решение.


person Nick    schedule 24.08.2020    source источник
comment
Есть ли причина, по которой вы не делаете то, что делает стандартная библиотека, и возвращаете итератор? Затем вызывающий код может проверить итератор, и если он не равен итератору end, то он допустим для косвенного прохождения.   -  person NathanOliver    schedule 24.08.2020
comment
@NathanOliver, будет много повторений этой проверки над проектом, поэтому ищите способ сформировать повторяющийся код в качестве подпрограммы.   -  person Nick    schedule 24.08.2020
comment
Я сомневаюсь, что вы сможете избежать этого, если захотите разрешить временные файлы. Временное продление срока службы не проходит через функции, поэтому невозможно получить lvalue из rvalue, которое вы передаете функции. Вы можете запретить rvalue, но не уверены, что это будет приемлемо.   -  person NathanOliver    schedule 24.08.2020
comment
Если бы был способ, это был бы единственный способ вернуть что-то из функций по умолчанию, не так ли? Это так удобно, просто верните ссылку, не думая о жизнях!   -  person n. 1.8e9-where's-my-share m.    schedule 24.08.2020
comment
Это не идеально, но может быть приемлемым решением, если нет другого. Будет ли template<class T> const T& get (key_type k, T&& def) = delete; достаточно или я должен также delete перегрузить до const T&&?   -  person Nick    schedule 24.08.2020
comment
get (key_type k, T&& def) = delete; было бы плохо, так как это также мешает вам принимать значения lvalue (благодаря правилам свертывания ссылок). Я думаю, что get (key_type k, const T&& def) = delete; должно работать.   -  person NathanOliver    schedule 24.08.2020


Ответы (1)


Нет, ты не можешь. Временный объект активен только для этого оператора и будет уничтожен до того, как вы получите к нему доступ через возвращенную ссылку.

const sometype &val = get(not_existing_key, get_temporary_object());
do_something_with(val);

Когда вы do_something_with(val), объект, к которому привязана ссылка val, уже уничтожен. Функция get не должна вызываться с временным объектом для параметра def. Вместо этого вы можете скопировать временный объект в переменную, а затем вызвать функцию со ссылкой на переменную.

auto copied_object = get_temporary_object();
const sometype &val = get(not_existing_key, copied_object);
do_something_with(val);

Теперь объект, к которому привязан val, находится в переменной copied_object.

person Jiho Park    schedule 24.08.2020
comment
Я полагаю, С++ не понял бы что-то вроде get(not_existing_key, (auto copied_object = get_temporary_object));? Наверное в вашем ответе должно быть ...get(not_existing_key, copied_object)? Во всяком случае, я не совсем понимаю, что именно std::move и std::copy делают с возражением, чем... - person Nick; 24.08.2020