[statechart] Template States, Compile Error

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

[statechart] Template States, Compile Error

greened
The attached testcase doesn't compile with g++ 4.0.2 or g++ 3.2.3.
The compiler generates a series of error messages like this:

boost/statechart/simple_state.hpp:189: error: no type named
'inner_context_type' in 'struct Test::NormalMode<int>'

I hastily sketched this out based on a larger code.  If there
are typos or other mistakes, let me know but the main problem I'm
trying to solve is the "no type named" problem.  I typedef it
right in the template definition for NormalMode!

This is using the current CVS for statechart, 1.33.1 for mpl.

Is it possibly a compiler bug?

Thanks!

                             -Dave

----------------
Testcase

#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/event.hpp>
#include <boost/statechart/custom_reaction.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/mpl/list.hpp>

#include <iostream>

// Switch finite state machine for multiplexor schedule policy
namespace Test {
   namespace sc = boost::statechart;
   namespace mpl = boost::mpl;

   // Inner states
   template <typename Type> struct On;
   template <typename Type> struct Off;

   template <typename Type> struct Error;

   // Outer states
   template <typename Type> struct NormalMode;
   template <typename Type> struct ErrorMode;

   // Events
   struct End : public sc::event<End> {};

   struct UnconsumedEvent : public sc::event<UnconsumedEvent> {
         std::string st;
         UnconsumedEvent(const std::string &s) : st(s) {};
       
         const std::string &state(void) const { return(st); };
   };

   template<typename Derived, typename Type>
   struct SwitchEvent : public sc::event<Derived> {
         typedef Type value_type;

         value_type ev;

         SwitchEvent(value_type e) : ev(e) {};

         value_type value(void) const { return(ev); }
   };

   template<typename Type>
   struct TurnOn : public SwitchEvent<TurnOn<Type>, Type> {
         TurnOn(Type value) : SwitchEvent<TurnOn<Type>, Type>(value) {};
   };

   template<typename Type>
   struct TurnOff : public SwitchEvent<TurnOff<Type>, Type> {
         TurnOff(Type value) : SwitchEvent<TurnOff<Type>, Type>(value) {};
   };

   template<typename Type> struct Switch;

   namespace detail {
      template<typename Type>
      struct typedefs {
            typedef Type value_type;
       
            typedef Switch<value_type> switch_context;
       
            typedef TurnOn<value_type> turn_on;
            typedef TurnOff<value_type> turn_off;

            typedef On<value_type> on;
            typedef Off<value_type> off;
      };
   };

   // The state machine
   template<typename Type>
   struct Switch :
         public sc::state_machine<Switch<Type>,
                                  NormalMode<Type> >,
         public detail::typedefs<Type>
   {
         typedef sc::state_machine<Switch<Type>,
                                   NormalMode<Type> > Base;
         typedef Switch<Type> This;

         std::string state(void) const {
            if (this->template state_cast<const typename This::on *>()) {
               return("ON");
            }
            else if (this->template state_cast<const typename This::off *>()) {
               return("OFF");
            }
            else {
               std::cerr << "Unknown state" << std::endl;
               std::abort();
               return("ERROR");
            }
         };

         // Abort on unexpected events
         void unconsumed_event(const sc::event_base &event)
         {
            std::cerr << "Unexpected event in state " << state() << std::endl;
            std::abort();
            this->post_event(new UnconsumedEvent(state()));
         };
   };

   // Define states

   // Outer
   template<typename Type>
   struct NormalMode : public sc::simple_state<NormalMode<Type>,
                                               Switch<Type>,
                                               Off<Type> >,
                       public detail::typedefs<Type> {
         typedef sc::simple_state<NormalMode<Type>,
                                  Switch<Type>,
                                  Off<Type> >
         state_base;
       
         typedef typename state_base::inner_context_type inner_context_type;
   };


   template<typename Type>
   struct ErrorMode : public sc::simple_state<ErrorMode<Type>,
                                              Switch<Type>,
                                              Error<Type> >,
                      public detail::typedefs<Type> {
         typedef sc::simple_state<ErrorMode<Type>,
                                  Switch<Type>,
                                  Error<Type> >
         state_base;

         typedef typename state_base::inner_context_type inner_context_type;
   };


   // Inner
   template<typename Type>
   struct Off : public sc::simple_state<Off<Type>,
                                        NormalMode<Type> >,
                public detail::typedefs<Type> {
         typedef Off<Type> This;
       
         typedef mpl::list<
            sc::custom_reaction<typename This::on>,
            sc::custom_reaction<End>
         > reactions;

         sc::result react(const typename This::on &) {
            this->template context<typename
This::switch_context>().transit("OFF", "ON");
            return(this->template transit<typename This::on>());
         };

         sc::result react(const End &) {
            this->terminate();
         };
   };

   template<typename Type>
   struct On : public sc::simple_state<On<Type>,
                                       NormalMode<Type> >,
               public detail::typedefs<Type> {
         typedef On<Type> This;

         typedef mpl::list<
            sc::custom_reaction<typename This::off>,
            sc::custom_reaction<End>
         > reactions;

         sc::result react(const typename This::off &) {
            this->template context<typename
This::switch_context>().transit("ON", "OFF");
            return(this->template transit<typename This::off>());
         };

         sc::result react(const End &) {
            this->terminate();
         };
   };

   template<typename Type>
   struct Error : sc::simple_state<Error<Type>,
                                   ErrorMode<Type> >,
                  public detail::typedefs<Type> {
   };
};

int main(void)
{
   Test::Switch<int> machine;

   machine.initiate();

   machine.process_event( Test::TurnOn<int>(0) );
   std::cout << "Now in state " << machine.state() << std::endl;
   machine.process_event( Test::TurnOff<int>(0) );
   std::cout << "Now in state " << machine.state() << std::endl;
   machine.process_event( Test::TurnOff<int>(0) );  // Should produce error
   std::cout << "Now in state " << machine.state() << std::endl;

   machine.process_event( Test::End() );
}
_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [statechart] Template States, Compile Error

Andreas Huber-2
Hi Dave

> The attached testcase doesn't compile with g++ 4.0.2 or g++ 3.2.3.
> The compiler generates a series of error messages like this:
>
> boost/statechart/simple_state.hpp:189: error: no type named
> 'inner_context_type' in 'struct Test::NormalMode<int>'

MSVC7.1 gives a similar diagnostic.

> I hastily sketched this out based on a larger code.  If there
> are typos or other mistakes, let me know but the main problem I'm
> trying to solve is the "no type named" problem.  I typedef it
> right in the template definition for NormalMode!

Strange indeed. As you might have noticed, I'm using templated states
and machines quite extensively in examples & tests. This should work in
principle. I'll look into it.

> This is using the current CVS for statechart, 1.33.1 for mpl.
>
> Is it possibly a compiler bug?

I don't think so, see above.

Later,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [statechart] Template States, Compile Error

greened
Andreas Huber wrote:

> Strange indeed. As you might have noticed, I'm using templated states
> and machines quite extensively in examples & tests. This should work in
> principle. I'll look into it.

Thanks.  Could you keep me posted on what you find?  Boost.Statechart
is perfect for the project I'm working on right now and it would be
a shame to have to drop it due to this issue.

                               -Dave
_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [statechart] Template States, Compile Error

Andreas Huber-2
David Greene wrote:
> Andreas Huber wrote:
>
>> Strange indeed. As you might have noticed, I'm using templated states
>> and machines quite extensively in examples & tests. This should work
>> in principle. I'll look into it.
>
> Thanks.  Could you keep me posted on what you find?

Will do, I'm working on it right now.

Later,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [statechart] Template States, Compile Error

Andreas Huber-2
In reply to this post by greened
It is getting late here in Switzerland. I've tried several things,
nothing worked and I don't have much of a clue at the moment. The fact
that two independent compilers choke on this pretty much rules out a
compiler bug. I think a library bug isn't likely either as everything
works when you make the innermost state non-templated. Moreover, the
newest version of TransitionTest.cpp (checked in yesterday) seems to
work perfectly on a number of platforms. That test does something very
similar to what you try to do. I can't currently see any other
explanation than that we must both be missing something. The attached
program is what I got after throwing out all the unnecessary stuff. It
compiles on MSVC, but as soon as you uncomment the commented parts it
complains with "'inner_context_type' : is not a member of
'NormalMode<Type>'". Tomorrow I'll try to reduce it to something that
hasn't anything to do with Boost.Statechart...

#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>

namespace sc = boost::statechart;
namespace mpl = boost::mpl;

template< typename Type > struct NormalMode;
struct Switch : sc::state_machine< Switch, NormalMode< int > > {};

/*template< typename Type >*/ struct Off;
template< typename Type >
struct NormalMode : sc::simple_state< NormalMode< Type >, Switch, Off/*<
Type >*/ >
{
};

//template< typename Type >
struct Off : sc::simple_state< Off/*< Type >*/, NormalMode< int > >
{
};

int main()
{
  Switch machine;
  machine.initiate();
  return 0;
}

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [statechart] Template States, Compile Error

greened
Andreas Huber wrote:

> It is getting late here in Switzerland. I've tried several things,
> nothing worked and I don't have much of a clue at the moment. The fact
> that two independent compilers choke on this pretty much rules out a
> compiler bug. I think a library bug isn't likely either as everything
> works when you make the innermost state non-templated. Moreover, the
> newest version of TransitionTest.cpp (checked in yesterday) seems to
> work perfectly on a number of platforms. That test does something very
> similar to what you try to do. I can't currently see any other
> explanation than that we must both be missing something. The attached
> program is what I got after throwing out all the unnecessary stuff. It
> compiles on MSVC, but as soon as you uncomment the commented parts it
> complains with "'inner_context_type' : is not a member of
> 'NormalMode<Type>'". Tomorrow I'll try to reduce it to something that
> hasn't anything to do with Boost.Statechart...

Believe me, I share your pain, bewilderment and frustration.  I
wonder if anyone else on the Boost developers list or someone on
comp.lang.c++.moderated would have any insight.

                          -Dave
_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

[Solution] Re: [statechart] Template States, Compile Error

Andreas Huber-2
Hi Dave

The problem you stumbled upon is (or was :-() well known. It was
discussed during review and I even tried to find a workaround for it not
too long ago. The solution is very simple and is even described in the
reference manual under the requirements for the InnerInitial parameter:
<quote>
An mpl::list<> containing models of the SimpleState or State concepts or
instantiations of the shallow_history or deep_history class templates.
If there is only a single inner initial state
_that_is_not_a_template_instantiation_ then it can also be passed
directly, without wrapping it into an mpl::list<>. [...]
</quote>

(_Note_the_underlined_part_). So, the only thing you need to do is to
wrap every templated InnerInitial parameter into an mpl::list and
everything will work as expected (see attached example). The reason why
compilers rightly choke on the code lies in the fact that simple_state
internally checks whether the InnerInitial parameter already is an
mpl::list. This check works perfectly even on forward-declared classes.
However, as soon as InnerInitial is a class template instantiation, for
some reason that template needs to be fully instantiated. The problem is
described in more detail here:
<http://article.gmane.org/gmane.comp.lib.boost.devel/128741>

I guess it was simply a little too late yesterday, sorry...

#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/mpl/list.hpp>

namespace sc = boost::statechart;
namespace mpl = boost::mpl;

template< typename Type > struct NormalMode;
struct Switch : sc::state_machine< Switch, NormalMode< int > > {};

template< typename Type > struct Off;
template< typename Type >
struct NormalMode : sc::simple_state<
  // Note that Off< Type > is wrapped into an mpl::list
  NormalMode< Type >, Switch, mpl::list< Off< Type > > >
{
};

template< typename Type >
struct Off : sc::simple_state< Off< Type >, NormalMode< Type > >
{
};

int main()
{
  Switch machine;
  machine.initiate();
  return 0;
}

HTH,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [Solution] Re: [statechart] Template States, Compile Error

greened
Andreas Huber wrote:

> (_Note_the_underlined_part_). So, the only thing you need to do is to
> wrap every templated InnerInitial parameter into an mpl::list and
> everything will work as expected (see attached example). The reason why

Aha, I see.  Yes, that makes sense.  Thanks for doing the digging.

Perhaps this should be part of a Statechart FAQ?  I certainly
glossed right over the part of the manual that noted this.  It's
easy to miss a single phrase like that.

                            -Dave
_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [Solution] Re: [statechart] Template States, Compile Error

Andreas Huber-2
David Greene wrote:
> Aha, I see.  Yes, that makes sense.  Thanks for doing the digging.
>
> Perhaps this should be part of a Statechart FAQ?

Already on my to-do list :-)...

Regards,

--
Andreas Huber

When replying by private email, please remove the words spam and trap
from the address shown in the header.

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users