#c #c 20 #rvalue-reference #perfect-forwarding #forwarding-reference
#c #c 20 #rvalue-ссылка #идеальная пересылка #пересылка-ссылка
Вопрос:
Рассмотрим функцию, подобную этой:
autoamp;amp; just(autoamp;amp; arg) { return std::forward<decltype(arg)>(arg); }
Это улучшит пересылку всех ссылок и вернет мертвую ссылку при вызове для временного объекта.
Подробнее:
struct Something {};
auto something() { return Something{}; }
autoamp;amp; ref = just(something()); // ERROR: Here ref refers to already destructed Something.
autoamp;amp; hold = something();
autoamp;amp; ref = just(hold); // OK: Here ref refers to lifetime-extended Something.
Итак, вопрос: как можно определить just
, чтобы первый вызов не смог скомпилироваться, а второй вызов будет скомпилирован?
Комментарии:
1. Требуется ссылка на значение lvalue ?
2.
just(autoamp;amp; arg)
гм, какую версию C вы используете? Эта функция не должна компилироваться в c 11, 14 или 17 без-fconcepts
.3. @Elliott Да,
gcc-9.3
с-std=c 17 -fconcepts
4. isocpp.github.io/CppCoreGuidelines/…
5. @Vahagn, нет проблем. Кроме того, концептуальный ответ не сработал бы, если тип аргумента шаблона равен rvalue . Так
just<Somethingamp;amp;>(std::move(hold))
будет компилироваться, что, я думаю, было не тем, что хотел сделать AndyG. Это можно было бы легко исправить, изменив его на что-то вродеrequires std::is_lvalue_reference_v<T>
или более интуитивноis_lvalue_reference_v<Tamp;amp;>
.
Ответ №1:
Как πάντα ῥεῖ
указано в комментариях, если вам требуется значение lvalue, вы должны написать свою функцию таким образом (single amp;
):
[из вашего комментария я использовал стиль c 17]
template <typename Arg>
auto amp;amp; just(Arg amp; arg);
Однако я буду считать, что ваша реальная проблема не так проста и что вы предпочитаете кодировать требования внутри функции:
#include <type_traits>
template <typename Arg>
auto amp;amp; just(Arg amp;amp; arg) {
static_assert(std::is_lvalue_reference_v<Argamp;amp;>);
return std::forward<Arg>(arg);
}
Пример: для функции целесообразно выполнить некоторую работу, а затем вернуть выходные данные функции с идеальной пересылкой, чтобы избежать копий, но вам нужно проверить ее возвращаемый тип. Для тех, кто не может использовать concepts
, лучше выполнить проверку внутри функции:
#include <iostream>
#include <type_traits>
template <typename Func>
auto amp;amp; just (Func amp;amp; func)
{
using return_type = decltype(func());
static_assert(std::is_reference_v<return_type>, "returning temportary");
// calculate arguments for func
// (no args here for simplicity)
return func(); // always return ref
}
int global;
int ReturnCopy () { return int(); }
int amp; ReturnGlobal () { return global; }
int amp;amp; ReturnTemporary () { return std::move(global); }
int main ()
{
just(ReturnCopy); // <--- error
just(ReturnGlobal);
just(ReturnTemporary);
}