Рекурсивное определение функции typedef: std:: function возвращает свой собственный тип
Я пытаюсь реализовать государственную машину. Состояние представлено функцией типа callback_t
: callback_t(int&)
, которая возвращает функцию того же типа.
Я не знаю, как реализовать его, поскольку функция рекурсивного ввода не допускается.
Вот что я пытался (как игрушка):
#include <stdio.h>
#include <functional>
typedef std::function< callback_t(int &) > callback_t ;
callback_t f1(int & i)
{
i++;
return f1;
}
callback_t f0(int & i)
{
if(i==0) i++;
return f1;
}
callback_t start(int & i)
{
i=0;
return f0;
}
int main(int argc, char **argv)
{
callback_t begin = start;
int i=0;
while(i<100)
begin = begin(i);
printf("hello world\n");
return 0;
}
Ошибка:
C:/work/tests/tests/main.cpp:4:41: error: 'callback_t' was not declared in this scope
typedef std::function< callback_t(int &) > callback_t ;
^
Есть ли способ реализовать такое поведение?
Env: win7, codelite, mingw 4.8.1
Ответы
Ответ 1
Поскольку определение рекурсивного типа невозможно, вы можете объявить структуру, которая несут функцию и неявно ее отличает:
template< typename... T >
struct RecursiveHelper
{
typedef std::function< RecursiveHelper(T...) > type;
RecursiveHelper( type f ) : func(f) {}
operator type () { return func; }
type func;
};
typedef RecursiveHelper<int&>::type callback_t;
Пример: http://coliru.stacked-crooked.com/a/c6d6c29f1718e121
Ответ 2
Небольшая библиотека для подстановки одного типа для другого:
template<class T>struct tag{using type=T;};
template<class X, class A, class B> struct subst:tag<X>{};
template<class X, class A, class B>
using subst_t=typename subst<X,A,B>::type;
template<class A, class B> struct subst<A,A,B>:tag<B>{};
template<class X, class A, class B>
struct subst<X&,A,B>:tag<subst_t<X,A,B>&>{};
template<class X, class A, class B>
struct subst<X&&,A,B>:tag<subst_t<X,A,B>&&>{};
template<class X, class A, class B>
struct subst<X const,A,B>:tag<subst_t<X,A,B>const>{};
template<class X, class A, class B>
struct subst<X volatile,A,B>:tag<subst_t<X,A,B>volatile>{};
template<class X, class A, class B>
struct subst<X const volatile,A,B>:tag<subst_t<X,A,B>const volatile>{};
template<template<class...>class Z,class...Xs, class A, class B>
struct subst<Z<Xs...>,A,B>:tag<Z<subst_t<Xs,A,B>...>>{};
template<template<class,size_t>class Z,class X,size_t n, class A, class B>
struct subst<Z<X,n>,A,B>:tag<Z<subst_t<X,A,B>,n>>{};
template<class R,class...Xs, class A, class B>
struct subst<R(Xs...),A,B>:tag<subst_t<R,A,B>(subst_t<Xs,A,B>...)>{};
теперь мы его используем:
struct own_type {};
template<class Sig>
struct recursive_func{
using func=std::function< subst_t<Sig, own_type, recursive_func> >;
template<class...Ts>
std::result_of_t<func const&(Ts...)>
operator()(Ts&&...ts)const{
return f(std::forward<Ts>(ts)...);
}
operator func const&()const&{return f;}
operator func&()&{return f;}
operator func()&&{return std::move(f);}
template<class F,
class=std::enable_if_t<
!std::is_same<recursive_func,std::decay_t<F>>::value
&& std::is_convertible<F,func>::value
>
>
recursive_func(F&&fin):f(fin){}
func* operator->(){return f;}
func const* operator->()const{return f;}
private:
func f;
};
который дает вам прекрасный синтаксис:
recursive_func< std::vector<own_type>() > f;
- это функция, которая возвращает вектор своего типа.
Это использует небольшое количество псевдонимов С++ 14 _t
. std::blah_t<?>
можно заменить на typename std::blah<?>::type
, если ваш компилятор строго С++ 11. Могут быть другие опечатки.
Слабость заключается в том, что шаблоны, которые ожидают, что их типы удовлетворяют некоторому свойству в непосредственном контексте, могут терпеть неудачу при подаче own_type
. Это можно исправить с помощью отложенного шаблона-аппликатора, который понимает subst
, но при случайном использовании вряд ли будет проблемой.
живой пример
Ответ 3
typedef std::function< callback_t(int &) > callback_t ;
**********
Вы пытаетесь определить новый тип с самим определением. Это невозможно! Вы не можете использовать callback_t до его определения.