Template parameter problem

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::parsedTuples::parsedTuple_2<T0, T1>::parsedTuple_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
 
V

Victor Bazarov

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::parsedTuples::parsedTuple_2<T0, T1>::parsedTuple_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 :)

Try changing your "p_.to<T2>(1)" to "this->p_.template to<T2>(1)" (the
'this->' part you already got, now add the 'template' keyword there).

V
 
M

max_sang

That works fine (although I need a bit of preprocessor hackery to
ensure it works on both platforms). Thank you very much, Victor -
you've saved me hours of investigation :-/
Regards
Max

PS Other readers - see Stroustrup C.13.6 for enlightenment :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,291
Messages
2,571,491
Members
48,148
Latest member
Benzed8701

Latest Threads

Top