M
max_sang
Hello
I have a nasty problem... take a look at this code:
struct Parser {
Parser(const string& s) { ... tokenizes s into pieces... }
template <class T> to(size_t idx);
private:
vector<string> tokens_; // holds the pieces of s
};
template <>
int Parser::to<int>(size_t idx)
{
return atoi(tokens_[idx].c_str());
}
.... more specializations ...
This parser class just slices up a string into tokens (separated by
spaces, for example)
and clients can call myParser.to<Fred>(4) to use the specialization of
Parser::to(size_t)
which will turn the string at position 4 in the vector into a Fred
object. So far so good.
Now I have the following base class:
template <class T1>
class ParsedTuple_1 {
public:
T1 value1;
ParsedTuple_1(const string& s)
: p_(s), value1(p_.to<T1>(0)) { }
protected:
Parser p_;
};
Instantiating this in client code works fine. "So what?" you say; "It
doesn't do anything
useful!" That's true. The interesting thing is when you inherit from
it:
template <class T1, class T2>
class ParsedTuple_2 : public ParsedTuple_1<T1> {
public:
T2 value2;
ParsedTuple_2(const string& s)
: ParsedTuple_1(s), value2(p_.to<T2>(1)) { }
};
template <class T1, class T2, class T3>
class ParsedTuple_3 : public ParsedTuple_3<T1, T2> {
public:
T3 value3;
ParsedTuple_3(const string& s)
: ParsedTuple_2(s), value3(p_.to<T3>(2)) { }
};
... etc up to ten, twenty.. parameters.
This allows you to do things like
#include "Date.hh"
void f(const Date&);
string s("5 3.1 04/06/2005");
ParsedTuple_3<int, float, Date> pt(s);
f(pt.value3);
so the constructor of ParsedTuple_[N] uses the constructor of
ParsedTuple_[N-1]
to parse the first N-1 tokens in the string, and is only responsible
for parsing the
final token.
OK, it's a nice trick, and it works fine on Sun, but gcc complains when
it reaches
the initialiser for value2:
ParsedTuples.hh: In constructor
'Bloomberg:
arsedTuples:
arsedTuple_2<T0, T1>:
arsedTuple_2(const
std::string&)':
ParsedTuples.hh:78: error: 'p_' was not declared in this scope
ParsedTuples.hh:78: error: expected primary-expression before '>' token
The first error (using the p_ protected member of the base class) can
be cured by
using this->p_ instead of p_ (a recent clarification of the lookup
rules, a colleague tells me,
since in a templated context one of the parameters could have a member
called p_). The
second error has defeated me. The problem is the use of T2 in the call
to Parser::to<T2>(int)
and all more-derived classes. I have a test for up to 30 template
parameters, so you can imagine
the error messages ;-)
Anybody have any idea what I can do to fix the bug? (I assume it is a
bug, gcc 4.0 seems to
be excellent, and Sun WS 6 is, er, kind of old
Many thanks
Max
I have a nasty problem... take a look at this code:
struct Parser {
Parser(const string& s) { ... tokenizes s into pieces... }
template <class T> to(size_t idx);
private:
vector<string> tokens_; // holds the pieces of s
};
template <>
int Parser::to<int>(size_t idx)
{
return atoi(tokens_[idx].c_str());
}
.... more specializations ...
This parser class just slices up a string into tokens (separated by
spaces, for example)
and clients can call myParser.to<Fred>(4) to use the specialization of
Parser::to(size_t)
which will turn the string at position 4 in the vector into a Fred
object. So far so good.
Now I have the following base class:
template <class T1>
class ParsedTuple_1 {
public:
T1 value1;
ParsedTuple_1(const string& s)
: p_(s), value1(p_.to<T1>(0)) { }
protected:
Parser p_;
};
Instantiating this in client code works fine. "So what?" you say; "It
doesn't do anything
useful!" That's true. The interesting thing is when you inherit from
it:
template <class T1, class T2>
class ParsedTuple_2 : public ParsedTuple_1<T1> {
public:
T2 value2;
ParsedTuple_2(const string& s)
: ParsedTuple_1(s), value2(p_.to<T2>(1)) { }
};
template <class T1, class T2, class T3>
class ParsedTuple_3 : public ParsedTuple_3<T1, T2> {
public:
T3 value3;
ParsedTuple_3(const string& s)
: ParsedTuple_2(s), value3(p_.to<T3>(2)) { }
};
... etc up to ten, twenty.. parameters.
This allows you to do things like
#include "Date.hh"
void f(const Date&);
string s("5 3.1 04/06/2005");
ParsedTuple_3<int, float, Date> pt(s);
f(pt.value3);
so the constructor of ParsedTuple_[N] uses the constructor of
ParsedTuple_[N-1]
to parse the first N-1 tokens in the string, and is only responsible
for parsing the
final token.
OK, it's a nice trick, and it works fine on Sun, but gcc complains when
it reaches
the initialiser for value2:
ParsedTuples.hh: In constructor
'Bloomberg:
std::string&)':
ParsedTuples.hh:78: error: 'p_' was not declared in this scope
ParsedTuples.hh:78: error: expected primary-expression before '>' token
The first error (using the p_ protected member of the base class) can
be cured by
using this->p_ instead of p_ (a recent clarification of the lookup
rules, a colleague tells me,
since in a templated context one of the parameters could have a member
called p_). The
second error has defeated me. The problem is the use of T2 in the call
to Parser::to<T2>(int)
and all more-derived classes. I have a test for up to 30 template
parameters, so you can imagine
the error messages ;-)
Anybody have any idea what I can do to fix the bug? (I assume it is a
bug, gcc 4.0 seems to
be excellent, and Sun WS 6 is, er, kind of old
Many thanks
Max