Почему мне нужно указать возвращаемое значение для функции, которую я передаю комбинатору Y

Я написал Y комбинатор, например, такой:

template <class F>
struct Y{
F f;
Y(F _f) : f{_f} {}
template<class...arg_t>
auto operator()(arg_t&&...arg) {return f(*this,std::forward<arg_t>(arg)...);}
};

Это работает, но когда я попытался определить факториал

auto fact = Y{[](auto&& self, int n) {
if (n<=1) return 1;
return n*self(n-1);}};

это скомпилируется, но когда я назвал это как f(3) Clang застрял на вывод типа возврата. С явным типом возврата все работало нормально. Это ограничение вывода шаблона? Есть ли обходной путь?

3

Решение

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

[](auto&& self, int n) {
if (n<=1) return 1;
return n*self(n-1);
}

Это переводится как:

struct lambda
{
template <typename T1>
constexpr auto operator()(T1&&self, int n) const
{
if (n<=1)
return 1;
return n*self(n-1);
}
};

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

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

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

2

Другие решения

Вывод типа применяется к двум операторам возврата комбинатора Y безоговорочно, поскольку информация, хранящаяся в переменной n, не является константным выражением (выражением, известным компилятору во время компиляции). Таким образом, фиксированная точка не определяется типом удержания.

Если nЗначение известно во время компиляции, вывод типа будет успешным, пример:

struct fact_overloads{
template<class Self,int n>
constexpr auto
operator()(Self&& self, std::integral_constant<n>){
if constexpr (n<=1) return 1;
else return n * self(std::integral_constant<n-1>{});
};
};

auto fact = Y{fact_overloads{}};

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

1

По вопросам рекламы [email protected]