I am working through problems in Accelerated C++ We have a program which stores strings in vectors and outputs them according to certain rules. The original code fragment is as follows.
typedef vector<string> Rule;
typedef vector<Rule> Rule_collection;
typedef map<string, Rule_collection> Grammar;
// read a grammar from a given input stream
Grammar read_grammar(istream& in)
{
Grammar ret;
string line;
// read the input
while (getline(in, line)) {
// `split' the input into words
vector<string> entry = split(line);开发者_C百科
if (!entry.empty())
// use the category to store the associated rule
ret[entry[0]].push_back(
Rule(entry.begin() + 1, entry.end()));
}
return ret;
}
We are then asked to use lists instead of vectors.
So all the vectors above will now become lists.
The bit I am stuck on is how to deal with the line beginning ret[entry]].push_back etc. Also what to put in after Rule... I have tried using entry.begin() but that doesn't work.
Any assistance would be appreciated.
with list you can perform most of the operations you can with vector but you cannot use entry[0]
as there is no random-access.
entry.front()
will get that element instead.
Also you cannot add 1 to entry.begin()
because it is bi-directional and does not support +, but you can assign it to a temporary iterator then ++it
.
entry.begin ()
returns an iterator to the start of the list, whereas
entry [0]
for vector returns the first element, so I think you want something like the following
*(entry.begin ())
EDIT:
Hopefully I understood what you are asking... Other than that begin and end should return comparable values for both vector and list
You will need to replace your code with something like this:
ret[*(entry.begin())].push_back(
Rule(++(entry.begin()), entry.end()));
begin()
gives you an iterator to the beginning of the list. You could dereference the iterator, which gives you the first value...
ret[*(entry.begin())].push_back(...
Or you could use the front()
function, which returns the element at the front of a list (technically a reference, but should work in this case).
ret[entry.front()].push_back(...
EDIT:
As others have pointed out, this works provided entry
is a std::list<string>
, as you implied.
ret[entry[0]]
calls Grammar::operator[]
passing it a string
: the string contained in entry[0]
, which is the first string put in such vector by split
.
Supposing that split
returns a std::list
, you should just take the first element of the list:
ret[ entry.front() ] ... // where entry is a std::list<string>
This code is pretty generic- it should just work when you change the typedefs, except a couple of minor niggles like std::list
does not give random-access iterators, and since you don't show the code I can't speak about split
.
精彩评论