Как написать функцию шаблона, которая возвращает ссылку или значение?
Я хотел бы написать функцию шаблона, которая возвращает ссылку или значение в зависимости от некоторого выражения времени компиляции. То, что я пробовал до сих пор, выглядит примерно так:
template<typename T>
auto&& Func()
{
if constexpr (some_compile_time_expression)
{
return GetReferenceFromSomewhere();
}
else
{
return GetValueFromSomewhere();
}
}
Это отлично подходит для всех типов ссылок, но не работает для значений. Например, если GetValueFromSomewhere
возвращает Foo
, то компилятор выводит возвращаемый тип Func
как Foo&&
и предупреждает, что я возвращаю адрес временного.
Есть ли способ сделать эту работу, или я вынужден дразнить две ветки отдельно (через перегрузки функций или некоторые из них)?
Ответы
Ответ 1
Используйте decltype(auto)
для заполнителя типа return, он сохранит точную категорию значений функции, которую вы вызываете в операторе return
template<typename T>
decltype(auto) Func()
{
if constexpr (some_compile_time_expression_dependent_on_T)
{
return GetReferenceFromSomewhere();
}
else
{
return GetValueFromSomewhere();
}
}
Демо-версия
Ответ 2
Преторианский ответ идеален, но вы также можете узнать о std::conditional
, который имеет более широкое использование. Например, рассмотрим переменную- data_
типа int
и функцию-член, которая возвращает data_
либо по ссылке, либо по значению в зависимости от некоторого условия компиляции:
template <bool COND>
std::conditional_t<COND, int&, int> data() { return data_; }
Это было бы невозможно с помощью decltype(auto)
. Вы также можете использовать тот же метод для передачи аргументов функции по ссылке/значению:
template <bool COND>
void f(std::conditional_t<COND, int&, int> param);
Или вы можете переключаться между конструкторами копирования/перемещения:
class X {
X(std::conditional_t<some_cond, const X&, X&&>) = default;
X(std::conditional_t<some_cond, X&&, const X&>) = delete;
...
};
Так далее...