Can't figure out syntax error with templates/member function pointers

A

Aaron Walker

Greetings,

I'm attempting to write my first *real* template function that also deals with
a map of strings to member function pointers that is making the syntax a little
tricky to get right.

The function in question:

36: template <typename Container,
37: typename OutputIterator,
38: typename UnaryOp>
39: void
40: transform_fields_into_matches(
41: typename Container::const_iterator first,
42: typename Container::const_iterator last,
43: OutputIterator result,
44: const fields_type& fields,
45: const std::map<std::string,
46: const std::string& (Container::value_type::*)(void) const > & fm,
47: UnaryOp op)
48: {
49: typedef const std::string& (Container::value_type::*mfp)(void) const;
50:
51: util::Regex criteria;
52: const int cflags(options::eregex() ?
53: util::Regex::extended|util::Regex::icase : util::Regex::icase);
54:
55: for (; first != last ; ++first)
56: {
57: fields_type::const_iterator f;
58: for (f = fields.begin() ; f != fields.end() ; ++f)
59: {
60: /* check if field is valid */
61: std::map<std::string, mfp>::const_iterator i = fm.find(f->first);
62: if (i == fm.end())
63: throw InvalidField(f->first);
64:
65: /* it's valid, so compile regex */
66: criteria.assign(f->second, cflags);
67:
68: /* compare criteria against the return value of the
69: * Container::value_type member function mapped to
70: * this field. */
71: const typename Container::value_type& v(*first);
72: if (criteria != (v.*(i->second))())
73: break;
74:
75: /* we're on the last field, meaning all fields that came before
76: * it also matched, so save it finally. */
77: if ((f+1) == fields.end())
78: *result++ = op(*first);
79: }
80: }
81: }

For some reason I can't figure out, the compile keeps bailing on line 61 with:
"error: expected ';' before i".

I'm thinking maybe it has something to do with the lack of 'typename' when
using Container::value_type in the function pointer, but adding that seems to
cause another problem (maybe I'm not putting it in the right place?)

using:
typedef const std::string& (typename Container::value_type::*mfp)(void) const;

causes:
error: expected unqualified-id before ‘typename’
error: expected `)' before ‘typename’
error: expected initializer before ‘typename’

Any pointers in the right direction?

Much appreciated,
Aaron
 
J

John Harrison

Aaron said:
Greetings,

I'm attempting to write my first *real* template function that also deals with
a map of strings to member function pointers that is making the syntax a little
tricky to get right.

The function in question:

36: template <typename Container,
37: typename OutputIterator,
38: typename UnaryOp>
39: void
40: transform_fields_into_matches(
41: typename Container::const_iterator first,
42: typename Container::const_iterator last,
43: OutputIterator result,
44: const fields_type& fields,
45: const std::map<std::string,
46: const std::string& (Container::value_type::*)(void) const > & fm,
47: UnaryOp op)
48: {
[snip]


Any pointers in the right direction?

well I'm not sure of your actual question because that is wildly complex
syntax you have. But I can see that you are heading in the wrong direction.

Look at this simple code

#include <vector>

template <typename Container>
void f(typename Container::iterator i)
{
typename Container::value_type v;
}

int main()
{
std::vector<int> i;
f(i.begin());
}

It fails to compile. The reason is that the compiler cannot work out
what Container is. The rules of C++ prevent the compiler from deducing
the template argument when the function argument type is of the form
typename T::m.

If you ever got your code to compile you would face this issue and there
isn't a solution (other than specifying the template arguments explcitily).

To pass iterators to a template function you should do the following and
use iterator_traits if you want the value type.

#include <vector>

template <typename I>
void f(I i)
{
std::iterator_traits<I>::value_type v;
}

int main()
{
std::vector<int> i;
f(i.begin());
}

john
 
V

Victor Bazarov

Aaron said:
Greetings,

I'm attempting to write my first *real* template function that also
deals with
a map of strings to member function pointers that is making the
syntax a little tricky to get right.

The function in question:
[...]
61: std::map<std::string, mfp>::const_iterator i =
fm.find(f->first);
62: if (i == fm.end())

Please don't post line numbers. Just add a comment to the line you
want to mark.
For some reason I can't figure out, the compile keeps bailing on line
61 with: "error: expected ';' before i".

Add 'typename' at the beginning:

typename std::map said:
I'm thinking maybe it has something to do with the lack of 'typename'
when
using Container::value_type in the function pointer, but adding that
seems to cause another problem (maybe I'm not putting it in the right
place?)

Probably.

V
 
A

Aaron Walker

John said:
Aaron said:
Greetings,

I'm attempting to write my first *real* template function that also
deals with
a map of strings to member function pointers that is making the syntax
a little
tricky to get right.

The function in question:

36: template <typename Container,
37: typename OutputIterator,
38: typename UnaryOp>
39: void
40: transform_fields_into_matches(
41: typename Container::const_iterator first,
42: typename Container::const_iterator last,
43: OutputIterator result,
44: const fields_type& fields,
45: const std::map<std::string,
46: const std::string& (Container::value_type::*)(void)
const > & fm,
47: UnaryOp op)
48: {

[snip]


Any pointers in the right direction?

well I'm not sure of your actual question because that is wildly complex
syntax you have. But I can see that you are heading in the wrong direction.

<snip>

My question was why would this:

49: typedef const std::string& (Container::value_type::*mfp)(void) const;
....
61: std::map<std::string, mfp>::const_iterator i = fm.find(f->first);

produce this compile failure:

61: "error: expected ';' before i".

It fails to compile. The reason is that the compiler cannot work out
what Container is. The rules of C++ prevent the compiler from deducing
the template argument when the function argument type is of the form
typename T::m.

If you ever got your code to compile you would face this issue and there
isn't a solution (other than specifying the template arguments explcitily).

To pass iterators to a template function you should do the following and
use iterator_traits if you want the value type.

<snip>

I was wondering if it'd be able to deduce the container type, but hadn't gotten
that far due to the syntax error. I didn't realize I could get the value_type
from iterator_traits.

Thanks for helping with what would probably have been my next problem :)

Aaron
 
A

Aaron Walker

Victor said:
Please don't post line numbers. Just add a comment to the line you
want to mark.

Ah, ok apologies. I figured it'd make it easier on whoever was trying to help.
Will keep in mind next time.
Add 'typename' at the beginning:

typename std::map<...>::const_iterator i = ...

Yep, that does it.

Thanks,
Aaron
 

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
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top