Почему мне нужно указать возвращаемое значение для функции, которую я передаю комбинатору Y - PullRequest
0 голосов
/ 22 декабря 2018

Я написал 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 застрял при выводе типа возврата.С явным типом возврата все работало нормально.Это ограничение вычитания шаблона?Есть ли обходной путь?

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Вывод типа применяется к двум операторам возврата комбинатора 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 должно быть известно во время компиляции.

0 голосов
/ 22 декабря 2018

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

[](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);
    }
};

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

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

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

...