17

I am trying to implement a state-machine. The state is represented by a function of type callback_t : callback_t(int&) which returns a function of same type.

I dont know how to implement it since recursive typed function seems not to be allowed.

Here what I tryied (as a toy) :

#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;
}

The error:

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 ;
                                       ^

Is there a way to implement this kind of behaviour ?

Env : win7, codelite, mingw 4.8.1

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
norisknofun
  • 859
  • 1
  • 8
  • 24

3 Answers3

12

Since recursive type definition is not possible, you can declare a structure that carry the function and implicitly cast to it:

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;

Example: http://coliru.stacked-crooked.com/a/c6d6c29f1718e121

Arpegius
  • 5,817
  • 38
  • 53
  • I modified your sample to match my use case, works perfectly. – norisknofun May 19 '14 at 16:09
  • @norisknofun The best thing is that I do not understand how callback_t(int&) is converting to callback_t because it is different type! Some how it work but I wouldn't relay on it. – Arpegius May 19 '14 at 16:11
  • @Arpegius Probably because of the template constructor of `std::function` :) – Drax May 19 '14 at 16:30
  • 1
    @Drax Right i just forgot that `std::function` do a implicit conversion of return type :) it will not work with bare function pointer – Arpegius May 19 '14 at 16:35
  • I does not compile under vs2013. Any idea? If not, I will start another question ... – norisknofun May 20 '14 at 22:09
  • @Arpegius sorry to bother, but I don't get this line: `typedef std::function< RecursiveHelper(T...) > type;` What is RecursiveHelper(T...) in that case? To my understanding, std::function should be templated with a function prototype, so something like RETURN_TYPE (ARGS) – Ervadac Feb 03 '15 at 16:53
  • 1
    @Ervadac It is a function definition. A function that return a copy of RecursiveHelper, and get any parameter from that are pass to this template. – Arpegius Feb 03 '15 at 16:57
  • @Arpegius Well, that was fast thanks. I don't see why RecursiveHelper can be used without and cannot be used with it. This does not work: `typedef std::function< RecursiveHelper(T...) > type;` – Ervadac Feb 03 '15 at 17:05
  • @Ervadac It is a C++11 code. You cannot compile it without variadic template support. BTW it should be `typedef std::function< RecursiveHelper(T...) > type;` . – Arpegius Feb 03 '15 at 17:07
  • @Arpegius Yes I know and I know it compiles and works, I just talk about using RecursiveHelper as a return type without its template parameter. Ok got it thanks. – Ervadac Feb 03 '15 at 17:10
  • 1
    @Ervadac Look here: http://stackoverflow.com/questions/16938480/is-it-necessary-to-use-template-parameters-to-refer-to-same-class-inside-definit – Arpegius Feb 03 '15 at 17:13
  • 1
    Question is tagged as C++11, so consider `using` instead of `typedef`. – kfsone Feb 29 '16 at 21:34
6

A little library for substituting one type for another:

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>...)>{};

now we use it:

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;
};

which gives you a lovely syntax:

recursive_func< std::vector<own_type>() > f;

is a function that returns a vector of its own type.

This uses a smattering of C++14 _t aliases. std::blah_t<?> can be replaced with typename std::blah<?>::type if your compiler is strictly C++11. There may be other typos.

A weakness is that templates that expect their types to satisfy some property in the immediate context may fail when fed own_type. This can be fixed with a delayed template applicator that subst understands, but in casual use is unlikely to be a problem.

live example

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • I'm absolutely sure this answer can help me with http://stackoverflow.com/questions/37219718/how-do-you-make-a-recursive-template-typedef but I'm unsure how to apply it to a type, rather than to a function. – NeomerArcana May 14 '16 at 10:19
0
typedef std::function< callback_t(int &) > callback_t ;
                       **********

You try to define a new type with the definition itself. This is not possible! You can't use callback_t before it is defined.

Klaus
  • 24,205
  • 7
  • 58
  • 113