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

5
  • You compiled your program with -std=c++11 or -std=gnu++11, right?
    – usr1234567
    Commented May 19, 2014 at 14:27
  • 1
    g++ -c "C:/work/tests/tests/main.cpp" -std=c++11 -g -O0 -Wall -o ./Debug/main.o -I. -I. Commented May 19, 2014 at 14:44
  • Please provide a more descriptive title. As is, whoever finds this in their search results will not be able to judge if it is worth checking out because this title could describe anything. Commented May 19, 2014 at 15:54
  • @R. Martinho Fernandes : what do you think now ? Any suggestion ? Commented May 19, 2014 at 16:04
  • Cool, thanks for acting! Have a +1. Commented May 19, 2014 at 16:09

3 Answers 3

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

12
  • I modified your sample to match my use case, works perfectly. Commented May 19, 2014 at 16:09
  • 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
    Commented May 19, 2014 at 16:35
  • 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
    Commented Feb 3, 2015 at 16:57
  • 1
    @Ervadac Look here: stackoverflow.com/questions/16938480/…
    – Arpegius
    Commented Feb 3, 2015 at 17:13
  • 1
    Question is tagged as C++11, so consider using instead of typedef.
    – kfsone
    Commented Feb 29, 2016 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

1
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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.