c++boostboost-msm

Boost MSM compilation speedup


I am trying to reduce the compilation time of my project by using explicit template instantiation of a boost MSM state machine. However whenever I add explicit template instantiation my project wont compile.

You can find an example of the problem using the example from the documentation here: http://coliru.stacked-crooked.com/a/9850cae23afdada2. (It is a contrived example as there is only one translation unit but the errors are the same as when I use explicit template instantiation in my project.)

Does anybody know how to solve those compilation errors?

/usr/local/include/boost/msm/back/state_machine.hpp: In instantiation of 'boost::msm::back::state_machine<A0, A1, A2, A3, A4>::deferred_events_queue_t& boost::msm::back::state_machine<A0, A1, A2, A3, A4>::get_deferred_queue() [with A0 = player_; A1 = boost::parameter::void_; A2 = boost::parameter::void_; A3 = boost::parameter::void_; A4 = boost::parameter::void_; boost::msm::back::state_machine<A0, A1, A2, A3, A4>::deferred_events_queue_t = std::deque<std::pair<boost::function<boost::msm::back::HandledEnum()>, bool>, std::allocator<std::pair<boost::function<boost::msm::back::HandledEnum()>, bool> > >]':
main.cpp:271:27:   required from here
/usr/local/include/boost/msm/back/state_machine.hpp:1346:40: error: 'struct boost::msm::back::state_machine<player_>::deferred_msg_queue_helper<boost::msm::back::state_machine<player_>, int>' has no member named 'm_deferred_events_queue'
         return m_deferred_events_queue.m_deferred_events_queue;
                ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
...

Solution

  • What you are trying to do unfortunately doesn't work because of some differences between how explicit and implicit instantiation work:

    Implicit instantiation

    If you implicitly instantiate a template (like you would normally when you use your state machine), the compiler will not necessarily generate code for all the member functions:

    The implicit instantiation of a class template specialization causes

    • the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friend

    C++ standard draft, [temp.inst/2]

    Explicit instantiation

    When you explicitly instantiate a template (as you tried above), the compiler will treat each member function as explicitly instantiated, which means that it will try to compile those as well.

    An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes and members that are templates) [...]

    C++ standard draft, [temp.explicit/10]

    With MSM

    In this particular case, the difference lies in the get_deferred_queue member function. It will only compile if the deferred_msg_queue_helper offers a particular member, which is only the case if your states support deferred events. Normally, you do not call that function, so the compiler never attempts to instantiate and then compile it. However, the explicit instantiation makes the compiler try - and fail - to compile get_deferred_queue in your state machine. Apparently, this is desired standard behavior, so the only workaround for you is to support deferred events in your state machine as described in the documentation

    Unfortunately, it is very much possible that you will run into additional problems with other features that are normally be switched off at compile-time. The next issue I encountered involves the visit_current_states function - to fix that, I had to add a custom base state with visitor functionality as described here. That made it compile without errors, although I am not entirely certain what impact those changes actually have.