for (p = a; p != a + n; ++p) {
mung(*p);
}
for (it = c.begin(); it != c.end(); ++it) {
mung(*it);
}
std::for_each(c.begin(), c.end(), mung);
The name ``lvalue'' comes originally from the assignment expression E1 = E2, in which the left operand E1 is required to be a (modifiable) lvalue. It is perhaps better considered as representing an object ``locator value''. What is sometimes called ``rvalue'' is in this International Standard described as the ``value of an expression''. An obvious example of an lvalue is an identifier of an object. As a further example, if E is a unary expression that is a pointer to an object, *E is an lvalue that designates the object to which E points.
operator+(Type1 lhs, Type2 rhs)
is the
name
of the function to be called for an expression
t2 + t2
For those who attend the kind of party where they talk about this kind of thing.
Σ: set of symbols (or letters)
w:
ordered sequence of symbols (string)
ε: empty string
L ⊂ Σ:
set of words
(Σ, S, s0, δ, F)
where
Σ:
set of symbols
S:
set of states
s0:
initial state
δ: (Σ, S) → S
next state
F ⊂ S: set of final (accepting) states
F);
otherwise the input word is rejected
L(M):
set of words (language) accepted by machine
M
ε-transitions:
spontaneous state
change without consuming input (consumes
ε,
the empty string)
Problem: converting a string to a floating point number. The practical solution is to make the appropriate library call. To understand how to do it, do it yourself at least once.
Finite-state automaton to recognize floating-point numbers.
Observe that we may produce the following equivalent automaton
with one-fewer state by combining states
s4
and
s5:
2 * 3 * 2 = 12 combinations
Legal states and transitions in tabular form:
| State | Event | |||||
|---|---|---|---|---|---|---|
| OPEN_DOOR | CLOSE_DOOR | SET_TIMER | PRESS_START | PRESS_CANCEL | DING! | |
|
1
(closed, unset, off) |
7 | invalid | 3 | 1 | 1 | invalid |
|
2
(closed, unset, on) invalid |
||||||
|
3
(closed, set, off) |
9 | invalid | 3 | 6 | 1 | invalid |
|
4
(closed, unset, on) invalid |
||||||
|
5
(closed, running, off) invalid (simple microwave) |
||||||
|
6
(closed, running, on) |
9 | invalid | 6 | 6 | 3 | 1 |
|
7
(open, unset, off) |
invalid | 1 | 9 | 7 | 7 | invalid |
|
8
(closed, unset, on) invalid |
||||||
|
9
(open, set, off) |
invalid | 3 | 9 | 9 | 7 | invalid |
|
10
(open, set, on) invalid |
||||||
|
11
(open, running, off) invalid |
||||||
|
12
(open, running, on) invalid |
||||||
There are several ways to implement a state machine. Choices depend on the particular requirements and tradeoffs between flexibility and effiency.
The simplest implementation uses a switch statement:
State get_next_state(State s, Event e) {
switch(s) {
case STATE_CLOSED_UNSET_OFF:
switch(e) {
case EVENT_OPEN_DOOR:
return STATE_OPEN_UNSET_OFF;
case EVENT_SET_TIMER:
return STATE_CLOSED_SET_OFF;
case EVENT_PRESS_START:
case EVENT_PRESS_CANCEL:
return STATE_CLOSED_UNSET_OFF;
default:
cerr << "invalid event" << e << " in state " <<s "\n";
}
break;
//...
}
}
Another approach is to use a data structure, either a graph or a lookup table. As a lookup table, you may have something like this:
class Machine {
public:
Machine();
//...
State get_next_state(State s, Event e);
private:
map<State, map<Event, State>*> state_map_;
};
Machine::Machine() {
map<Event, State>* event_map = new map<Event, State>
state_map_[STATE_CLOSED_UNSET_OFF] = event_map
(*event_map)[EVENT_OPEN_DOOR] = STATE_OPEN_UNSET_OFF;
(*event_map)[EVENT_SET_TIMER] = STATE_CLOSED_SET_OFF;
(*event_map)[EVENT_PRESS_START] = STATE_CLOSED_UNSET_OFF;
(*event_map)[EVENT_PRESS_CANCEL] = STATE_CLOSED_UNSET_OFF;
//...
}
Machine::get_next_state(State s, Event e) {
return (*state_map[s])[e];
}