Комбинатор неподвижной точки в C++1х


Это было проверено и компиляции в Visual Studio 2010 с. Существуют ли серьезные проблемы с этой реализации?

ПС. Эта реализация полностью на основе лямбда-выражения. Если я могу сделать точка отсчета::исправление реальная функция-член будет проще, чем это.

//As decltype(variable)::member_name is invalid currently, 
//the following template is a workaround.
//Usage: t2t<decltype(variable)>::t::member_name
template<typename T>
struct t2t
{
    typedef T t;
};

template<typename R, typename V>
struct fixpoint
{
    typedef std::function<R (V)> func_t;
    typedef std::function<func_t (func_t)> tfunc_t;
    typedef std::function<func_t (tfunc_t)> yfunc_t;

    class loopfunc_t {
    public:
        func_t operator()(loopfunc_t v)const {
            return func(v);
        }
        template<typename L>
        loopfunc_t(const L &l):func(l){}
        typedef V Parameter_t;
    private:
        std::function<func_t (loopfunc_t)> func;
    };
    static yfunc_t fix;
};
template<typename R, typename V>
typename fixpoint<R, V>::yfunc_t fixpoint<R, V>::fix = 
[](fixpoint<R, V>::tfunc_t f) -> fixpoint<R, V>::func_t {
    fixpoint<R, V>::loopfunc_t l = [f](fixpoint<R, V>::loopfunc_t x) ->
        fixpoint<R, V>::func_t{
            //f cannot be captured since it is not a local variable
            //of this scope. We need a new reference to it.
            auto &ff = f;
            //We need struct t2t because template parameter
            //V is not accessable in this level.
            return [ff, x](t2t<decltype(x)>::t::Parameter_t v){
                return ff(x(x))(v); 
            };
        }; 
        return l(l);
    };

int _tmain(int argc, _TCHAR* argv[])
{
    int v = 0;
    std::function<int (int)> fac = 
    fixpoint<int, int>::fix([](std::function<int (int)> f)
        -> std::function<int (int)>{
        return [f](int i) -> int{
            if(i==0) return 1;
            else return i * f(i-1);
        };
    });

    int i = fac(10);
    std::cout << i; //3628800
    return 0;
}


1537
6
задан 23 июня 2011 в 11:06 Источник Поделиться
Комментарии
1 ответ

Я ВГА попробовал то же самое в G++ (версия 4.5 от Ubuntu 11.04 оригинал), и результат весьма впечатлил. Теперь у нас есть гораздо больше возможностей для generise решение.


  1. теперь мы можем поддерживать любое количество параметров без модификации кода.

  2. класс t2t уже не нужен, как G++ лямбда поддерживает доступ все идентификаторы в области, в том числе глобальных вещах.

Я также попытался написать шаблон функции для доступа к внутренней функции. И результат выглядит хорошо. Я просто хотел сказать: она шикарна!

#include <iostream>
#include <functional>

template<typename R, typename... V>
struct fixpoint
{
typedef std::function<R (V...)> func_t;
typedef std::function<func_t (func_t)> tfunc_t;
typedef std::function<func_t (tfunc_t)> yfunc_t;

class loopfunc_t {
public:
func_t operator()(loopfunc_t v)const {
return func(v);
}
template<typename L>
loopfunc_t(const L &l):func(l){}
loopfunc_t(){}
private:
std::function<func_t (loopfunc_t)> func;
};
static func_t Fix(tfunc_t f){
return [](loopfunc_t x){ return x(x); }
([f](loopfunc_t x){ return [f, x](V... v){ return f(x(x))(v...); }; });
}
};
template<typename T>
struct getfixpoint
{
typedef typename getfixpoint<decltype(&T::operator())>::fp fp;
};
template<typename R, typename T, typename... V>
struct getfixpoint<std::function<R (V...)> (T::*)(std::function<R (V...)>)>
{
typedef fixpoint<R, V...> fp;
};
template<typename R, typename T, typename... V>
struct getfixpoint<std::function<R (V...)> (T::*)(std::function<R (V...)>)const>
{
typedef fixpoint<R, V...> fp;
};
template<typename R, typename... V>
struct getfixpoint<std::function<R (V...)> (*)(std::function<R (V...)>)>
{
typedef fixpoint<R, V...> fp;
};

template<typename T>
auto getFix(T f) -> typename getfixpoint<T>::fp::func_t {
return getfixpoint<T>::fp::Fix(f);
};

int main(int argc, char* argv[])
{
auto fac = getFix([](std::function<int (int)> f) -> std::function<int (int)>{
return [f](int n)->int { if(n==0) return 1; else return n * f(n-1); };
});
std::cout<<fac(10)<<std::endl; //3628800
return 0;
}

3
ответ дан 26 июня 2011 в 10:06 Источник Поделиться