Как вывести тип возвращаемого значения из r-value ссылки? С++
Изучаю выведение типов в С++ и r-value ссылки. Есть шаблонный метод в классе, который принимает функцию в качестве аргумента:
template<typename Return>
Return then(Return&& function) const {
static_assert(std::is_invocable_v<Return>, "Return cant be called.");
return function();
}
И вызов метода:
int increment(int i) {
return i + 1;
}
int main() {
int a = myclass.then(increment);
return 0;
}
Данный код не компилируется, поскольку нельзя присвоить значение int()() переменной a. Я порылся в отладчике и понял, что при передаче функции в качестве r-value ссылки тип Return автоматически становится int()() в данном случае, а я хочу, чтобы метод вернул результат функции. Возможно ли вывести тип возвращаемого значения?
Ответы (1 шт):
Самый правильный вариант такой:
template <typename F>
decltype(auto) then(F &&function) const
{
return function();
}
Или, еще лучше, с forward:
template <typename F>
decltype(auto) then(F &&function) const
{
return std::forward<F>(function)();
}
Но раз вы не хотите, чтобы компилятор определял за вас тип, то так:
template <typename F>
auto then(F &&function) const -> decltype(function())
{
return function();
}
Или, еще лучше, с forward:
template <typename F>
auto then(F &&function) const -> decltype(std::forward<F>(function)())
{
return std::forward<F>(function)();
}
Здесь использован синтаксис trailing return type (замыкающий (т. е. написанный справа) возвращаемый тип). auto здесь не определяет тип сам, а просто означает, что настоящий тип написан справа, после ->.
Обычно тип функция(...) эквивалентно auto функция(...) -> тип. Но здесь мы вынуждены использовать второй вариант, потому что хотим использовать function в decltype, а левее списка параметров к нему нельзя обратится.
Есть другой вариант записи:
template <typename F>
decltype(std::declval<F>()()) func(F &&function) const
{
return std::forward<F>(function)();
}
Записывая возвращаемый тип слева, мы не можем использовать function в decltype, но можем использовать F.