Hi GCC gurus, I have an implementation of Y Combinator in C++, which works in GCC 4.9 to 5.1 as well as Clang 3.5 (in C++14 mode). It stops working in GCC 5.2 and 5.3. I cannot really whether it is a GCC bug or not, but it looks like GCC is being too eager in template instantiation. Would you please check?
--- The code begins --- #include <functional> #include <iostream> // Struct to wrap a function for self-reference. template <typename _Fn> struct self_ref_func { std::function<_Fn(self_ref_func)> fn; }; /** * Generates the fixed point using the simple fixed-point combinator. * This function takes a curried function of one parameter. * * @param f the second-order function to combine with * @return the fixed point */ template <typename _Rs, typename _Tp> std::function<_Rs(_Tp)> fix_simple( std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)> f) { // Y f = f (λx.(Y f) x) return f([f](_Tp&& x) { return fix_simple(f)(std::forward<_Tp>(x)); }); } /** * Generates the fixed point using the Curry-style fixed-point combinator. * This function takes a curried function of one parameter. * * @param f the second-order function to combine with * @return the fixed point */ template <typename _Rs, typename _Tp> std::function<_Rs(_Tp)> fix_curry( std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)> f) { // Y = λf.(λx.x x) (λx.f (λy.(x x) y)) typedef std::function<_Rs(_Tp)> fn_1st_ord; typedef self_ref_func<fn_1st_ord> fn_self_ref; fn_self_ref r = { [f](fn_self_ref x) { // λx.f (λy.(x x) y) return f(fn_1st_ord([x](_Tp&& y) { return x.fn(x)(std::forward<_Tp>(y)); })); } }; return r.fn(r); } int main() { using std::function; typedef function<int(int)> Func; typedef function<Func(Func)> FuncFunc; FuncFunc almost_fac = [](Func f) { return Func([f](int n) { if (n <= 1) return 1; return n * f(n - 1); }); }; auto const fac1 = fix_simple(almost_fac); auto const fac2 = fix_curry(almost_fac); std::cout << fac1(5) << std::endl; std::cout << fac2(5) << std::endl; } --- The code ends --- --- The error message begins --- In file included from test_gcc.cpp:1:0: /opt/local/include/gcc5/c++/functional: In substitution of 'template<class _Functor, class> std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = std::function<std::function<int(int)>(self_ref_func<std::function<int(int)> >)>; <template-parameter-1-2> = <missing>]': /opt/local/include/gcc5/c++/functional:1981:45: recursively required by substitution of 'template<class _Functor, class> std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = std::function<std::function<int(int)>(self_ref_func<std::function<int(int)> >)>; <template-parameter-1-2> = <missing>]' /opt/local/include/gcc5/c++/functional:1981:45: required by substitution of 'template<class _Functor, class> std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = std::function<std::function<int(int)>(self_ref_func<std::function<int(int)> >)>; <template-parameter-1-2> = <missing>]' test_gcc.cpp:47:51: required from 'fix_curry(std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)>)::<lambda(fn_self_ref)>::<lambda(_Tp&&)> [with _Rs = int; _Tp = int]' test_gcc.cpp:45:34: required from 'struct fix_curry(std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)>)::<lambda(fn_self_ref)> [with _Rs = int; _Tp = int; fn_self_ref = self_ref_func<std::function<int(int)> >]::<lambda(int&&)>' test_gcc.cpp:45:21: required from 'fix_curry(std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)>)::<lambda(fn_self_ref)> [with _Rs = int; _Tp = int; fn_self_ref = self_ref_func<std::function<int(int)> >]' test_gcc.cpp:43:10: required from 'struct fix_curry(std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)>) [with _Rs = int; _Tp = int]::<lambda(fn_self_ref)>' test_gcc.cpp:50:5: required from 'std::function<_Rs(_Tp)> fix_curry(std::function<std::function<_Rs(_Tp)>(std::function<_Rs(_Tp)>)>) [with _Rs = int; _Tp = int]' test_gcc.cpp:69:43: required from here /opt/local/include/gcc5/c++/functional:1981:69: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) using _Invoke = decltype(__callable_functor(std::declval<_Functor&>()) ^ compilation terminated. --- The error message ends --- Thanks for any help and advice. -- Wu Yongwei URL: http://wyw.dcweb.cn/