I'm migrating code from a server with Red Hat Enterprise Linux ES release 3 to a server with Red Hat Enterprise Linux release 7.5. The code compiles successfully on the RH 3 box (with gcc 3.2.3), but not on the RH 7.5 box (with gcc 4.8.5). Here's the header file code in question:
#ifndef FSM_H
#define FSM_H
#include <assert.h>
#include <string>
#include <map>
namespace fsm {
template<class A>
class Event {
bool (A::*Action)(void); // Action to peform. False means it failed.
std::string gotoState; // State to transition on success
public:
Event();
Event( const Event &rhs );
Event( bool (A::*Action)(void), const std::string &newState );
const std::string HandleEvent(A *parent) const;
};
template<class A>
class State : protected std::multimap<const std::string,Event<A> > {
public:
void addEvent( const std::string &event,
bool (A::*Action)(void),
const std::string &newState);
const std::string HandleEvent( A *parent, const std::string &event ) const;
};
template<class A>
void State<A>::addEvent(const std::string &event,
bool (A::*Action)(void),
const std::string &newState )
{
insert(State<A>::value_type(event,Event<A>( Action, newState )));
}
template<class A>
const std::string State<A>::HandleEvent( A *parent, const std::string &event ) const
{
typename State<A>::const_iterator i;
std::string newState;
for( i=lower_bound(event); i!=upper_bound(event); i++ ) {
newState = i->second.HandleEvent(parent);
if ( newState.size() ) return newState;
}
return std::string();
}
} // namespace fsm
#endif
The compiler complains about the insert
, lower_bound
, and upper_bound
functions; it can't find a matching function for each of these functions. These should be interpreted as functions belonging to std::map
, but the compiler appears to be trying to use std::upper_bound
and std::lower_bound
instead (I'm not sure what insert
function the compiler is trying to use).
In order to make it crystal-clear to the compiler, I modified the code so there was no ambiguity that lower_bound
, upper_bound
, and insert
are std::map
functions. For example, in this part of the code:
template<class A>
const std::string State<A>::HandleEvent( A *parent, const std::string &event ) const
{
typename State<A>::const_iterator i;
std::string newState;
for( i=lower_bound(event); i!=upper_bound(event); i++ ) {
newState = i->second.HandleEvent(parent);
if ( newState.size() ) return newState;
}
return std::string();
}
I modified the code as follows:
template<class A>
const std::string State<A>::HandleEvent( A *parent, const std::string &event ) const
{
typename State<A>::const_iterator i;
typename State<A>::const_iterator lowerBound;
typename State<A>::const_iterator upperBound;
std::string newState;
lowerBound = std::multimap<const std::string, fsm::Event<A>, std::less<const std::string>,
std::allocator<std::pair<const std::string, fsm::Event<A> > > >::lower_bound(event);
upperBound = std::multimap<const std::string, fsm::Event<A>, std::less<const std::string>,
std::allocator<std::pair<const std::string, fsm::Event<A> > > >::upper_bound(event);
for( i=lowerBound; i!=upperBound; i++ ) {
newState = i->second.HandleEvent(parent);
if ( newState.size() ) return newState;
}
return std::string();
}
That works, but it's hokey, verbose and ugly. Is there a better way to help the compiler know that it should use the functions from std::map
without having to spell it out in such a tedious manner?