public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* template problems
@ 2002-07-26  2:02 Thomas Maier
  0 siblings, 0 replies; 5+ messages in thread
From: Thomas Maier @ 2002-07-26  2:02 UTC (permalink / raw)
  To: gcc-help; +Cc: Thomas Maier

Hi everbody, 

hope this is the right mailing list. I got a problem compiling some C++
code (using "gcc version 2.95.3 20010315 (SuSE)" and also a 3.0 version,
see below).  I do not know if it is valid C++ actually but I guess it
is.  Question is: how can I scope deeper than level one in types used in
templates? :)  Well, if you use a template that gets a container type C
as parameter, you might want to say  "C::value_type some_var;" but in
order to say that you have to use typename:

typename C::value_type some_var;

That's fine.  Now how can I use value_type to "scope one level deeper",
say I want to take the address of some member function of value_type:

void (C::value_type::* some_member_function)();

Just saying

void (typename C::value_type::* some_member_function)();

fails, as does saying

void (typename C::typename value_type::* some_member_function)();

Putting parens just about everywhere did not help, too.  How do I have
to tell g++ to do what I want?  It works in a non-template function:

void f()
{
  {
    map<size_t,string>::mapped_type mt("ext");
    map<size_t,string>::key_type kt(42);
    map<size_t,string>::key_type (map<size_t,string>::mapped_type::* key_method)() const
      = &map<size_t,string>::mapped_type::size;
  }

  {
    typedef map<size_t,string> Cont;
    Cont::mapped_type mt("ext");
    Cont::key_type kt(42);
    Cont::key_type (Cont::mapped_type::* key_method)() const = &Cont::mapped_type::size;
  }
}

The second block is the same as the first one but it uses a typedef to
make things easier to read.  I wrote the first block only to see if the
typedef makes things work.  I attach a small file small.cc that you can
compile.

The problem is:

/*11*/ template <class Container> void
/*12*/ foo(Container& container, void (typename Container::mapped_type::* member_function)())
/*13*/ { }

which gives

g++ -Wall -c small.cc
small.cc:12: parse error before `*'
small.cc:12: `foo' declared as function returning a function


Probably g++ doesn't know that Container::mapped_type is a type.  You
even have to tell it that Container is a type, that's what that typename
is for.  I tried to cheat g++ with writing 

/*16*/ template <class Container, class MappedType = typename Container::mapped_type> void
/*17*/ foo(Container& container, void (MappedType::* member_function)())
/*18*/ { }

but it only said 

small.cc:18: default argument for template parameter in function template `foo(Container &, void (MappedType::*)())'

(Yes, sure it is, doesn't really sound like an error.  Is it one?  In
the Stroustrup there is an example with default arguments so I expected
it to work.) 

I also tried all that with "gcc version 3.0.1 (SuSE)".  Doesn't work. 
Unfortunately I am not able to just download and install the latest gcc
version to see if things work as I only have a very slow dial up
connection (and here in Germany they charge for connection *times*!
pfff...).  And unexperienced as I am that would probably make things
even worse :).  So is this a problem with g++ or with my understanding
of or my way of writing down C++?  And if it is the former, is it fixed
in 3.1 or will it be fixed in 3.2?  And please be so kind and cc any
follow-ups to me as I am not on this list (because of said f!$%&ing slow
modem :). 

Regards and advTHANKSance, Thomas. 



P.S.: Just in case you wonder why the hell I need this: Actually I
wanted to write an assoc_insert_iterator to insert a value into a map
like a back_inserter (gives a back_insert_iterator that) inserts into a
list, for example.  The iterator needs to be parameterized with some X
where it can get the value's key from.  Basically when I write
(simplified pseudo code) 

map<Key, Value> m; 
fill(assoc_inserter(m, X)); 

and fill(assoc_insert_iterator iter) calls iter's operator=, operator=
has to call some method or function "Key X(Value)" that I gave as a
parameter. 

Specifying functions works, see above.  But when I want to pass a method
(exploiting the fact that some classes have some method giving a
key-function) it doesn't, see above.

-- 
Thomas Maier <T.Maier@tu-bs.de>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: template problems
  2002-07-26 15:18   ` Thomas Maier
@ 2002-07-26 16:34     ` Gokhan Kisacikoglu
  0 siblings, 0 replies; 5+ messages in thread
From: Gokhan Kisacikoglu @ 2002-07-26 16:34 UTC (permalink / raw)
  To: Thomas Maier; +Cc: gcc-help

> 
> Key Value::key_method()
> 
> if is there and if not, via a global non-member function
> 
> Key key_function(Value)
> 

I understand your idea, but I am not sure whether it can be done with
the templates (I don't know). Simply create a key class and do the
lookup there while inserting;

make_pair( ket_class(data), data )

Maybe such a thing requires the key to be generated before the
insertion.

But better, it really sounds like the set class is more suitable for
your purpose, something like this;

class foo;	// so you have class of data

struct _aux_data_compare
{
    bool operator () (const foo &_x, const foo &_y)
    {
	return ( _x < _y ); // <==== you define this comparison!!!
    }
};

set <foo, _aux_data_compare> my_set;

HTH,
Gokhan

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: template problems
  2002-07-26 11:08 ` Gokhan Kisacikoglu
@ 2002-07-26 15:18   ` Thomas Maier
  2002-07-26 16:34     ` Gokhan Kisacikoglu
  0 siblings, 1 reply; 5+ messages in thread
From: Thomas Maier @ 2002-07-26 15:18 UTC (permalink / raw)
  To: kisa; +Cc: gcc-help

Thanks a lot for your quick and detailed answer.  However I guess I
couldn't make things clear.

On Fri, 2002-07-26 at 20:11, Gokhan Kisacikoglu wrote:
> I am not sure you can pass address of template functions, especially
> when these functions are relative to a certain instance (not static), I
> don't know how it would all work. Is this described in the ISO spec? I
> am not sure... Maybe somebody can tell us more...

Well, when I say

template<class Container> bla(some_arg) {...}

with "some_arg"'s type being dependant by Container (e.g.
Container::mapped_type) and call bla with 
map<size_t,string> for Container
then some_arg would be of type Container::mapped_type, i.e. string.  Is
there any reason the compiler cannot know this?  Well, the question
should probably be "Is this a special instance of more general problem
(joke intended) so the compiler cannot know in general?".  At least in
this case, string looks pretty concrete to me and nothing prevents me
from taking string's size() method's address in a non-template function
(see the example in my last mail, function f()).  Why can't I do that in
a template function?  I thought the problem is that I can only attribute
the first type with typename in a "deeper-than-one-level-scope".  But
maybe the actual problem is a different one.  To say it again: for
some_arg I can't say 

some_return_type (Container::mapped_type::* some_arg)()

and I thought it is only because I do not know where and how to place
typename keywords.  Only thing I can guess here is that the compiler
somehow does not have enough type information (you even have to tell it
that Container is a typename).  I checked it with a
"just-one-level-scope"

some_return_type (SomeTemplateType::* some_arg)()

This works, so I could move the information on which method to call to
get the value's keys to the fill method, see below.



> 
> > wanted to write an assoc_insert_iterator to insert a value into a map
> > like a back_inserter (gives a back_insert_iterator that) inserts into a
> > list, for example.  The iterator needs to be parameterized with some X
> 
> You can already do this, if you have your value_types (pair of key and
> data) stored in an array let's say, that you want to insert them into a
> map by using the insert_iterator, you could easily type the following;
> 
> #include <map>
> #include <vector>
> #include <iterator>
> #include <string>
> #include <iostream>
> 
> using namespace std; 	// for simplicity
> 
> // a simple mapping
> //
> typedef pair <int, string> int_string_pair;
> 
> typedef map <int_string_pair :: first_type, 
> 	    int_string_pair :: second_type> mapped_strings;
> 
> // a simple array (let's say)
> //	
> typedef vector <int_string_pair> map_value_array;
> 
> int main(void)
> {
>     // instances
>     //
>     
>     // value in an arrays
>     //	
>     map_value_array array;
>     
>     array.reserve(3);
>     array.push_back( make_pair( 1, "one" ) );
>     array.push_back( make_pair( 3, "three" ) );	// randomly ordered
>     array.push_back( make_pair( 2, "two" ) );
>     
>     // insert into a map instance
>     //	
>     mapped_strings mstrs;
>     
>     copy( array.begin(), array.end(), 
> 	insert_iterator <mapped_strings> (mstrs, mstrs.end()) );
>     
>     mapped_strings :: iterator iter = mstrs.begin();
>     cerr << iter->first << " " << iter->second << endl; ++ iter;
>     cerr << iter->first << " " << iter->second << endl; ++ iter;
>     cerr << iter->first << " " << iter->second << endl; ++ iter;
>     
>     assert( iter == mstrs.end() );
>     
>     return 0;
> }


Well, I wanted to write a function fill() that is able to fill a
container no matter if it is a sequence or some associative thingy.  I
do not have key-value-pairs.  I only have values, say of type Value. 
When I want to insert them into a list<Value> or vector<Value>, it's
easy, I use back_inserter() to get a back_insert_iterator.  But when I
want to insert them into a map<Key, Value>, I'd like to automatically
let the fill function get the keys via some method

Key Value::key_method()

if is there and if not, via a global non-member function

Key key_function(Value)


I can of course move the information which method (or function) to call
into the fill() function which works there, as the scope is only one
"::" because I parameterize fill with the value type Value and don't
need to get Value via Container::mapped_type.  So I end up with

typename Container::key_type (Value::*key_method)()

instead of

typename Container::key_type (Container::mapped_tpe::*key_method)()

which works.  But ad hoc I consider that solution less elegant and
general than having an assoc_insert_operator and thus having no need to
give fill() anything but such an iterator.  Maybe you have a different
opinion on this, feel free to tell me.

Hm, I'm just thinking that I wouldn't probably want to parameterize
fill() with Value because I already parameterize it either with
Container or with OutIter and I should be able to get Value type from
both of these.  Parameterizing assoc_insert_iterator or fill() with a
(very general) Operation type (like the standard functors do) and using
mem_fun and prt_fun stuff works, too.  But that seems overly general and
I'd like to restrict the types when I know something about them.  Damn,
I fiddled around to much with that.  I think I need to carefully rethink
what should be parameterized with how many and which types.  We're gonna
move during the next couple of days so I won't respond to any mail.  At
least I can think about this when I'm carrying boxes up to our new
apartment :).

> 
> check out:
> 
> http://www.sgi.com/tech/stl/insert_iterator.html
> 
> The second parameter is the hint to tell where to start the search for
> the appropriate insertion location in the case of map, it would be the
> exact insertion point in the case of list for example...
> 
> HTH,
> Gokhan

Yes, I know this one.  But thanks a lot anyway, have a good night, at
least now and here in Germany :), Thomas.

-- 
Thomas Maier <T.Maier@tu-bs.de>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: template problems
  2002-07-26  2:07 Thomas Maier
@ 2002-07-26 11:08 ` Gokhan Kisacikoglu
  2002-07-26 15:18   ` Thomas Maier
  0 siblings, 1 reply; 5+ messages in thread
From: Gokhan Kisacikoglu @ 2002-07-26 11:08 UTC (permalink / raw)
  To: Thomas Maier; +Cc: gcc-help, Thomas Maier

I am not sure you can pass address of template functions, especially
when these functions are relative to a certain instance (not static), I
don't know how it would all work. Is this described in the ISO spec? I
am not sure... Maybe somebody can tell us more...

> wanted to write an assoc_insert_iterator to insert a value into a map
> like a back_inserter (gives a back_insert_iterator that) inserts into a
> list, for example.  The iterator needs to be parameterized with some X

You can already do this, if you have your value_types (pair of key and
data) stored in an array let's say, that you want to insert them into a
map by using the insert_iterator, you could easily type the following;

#include <map>
#include <vector>
#include <iterator>
#include <string>
#include <iostream>

using namespace std; 	// for simplicity

// a simple mapping
//
typedef pair <int, string> int_string_pair;

typedef map <int_string_pair :: first_type, 
	    int_string_pair :: second_type> mapped_strings;

// a simple array (let's say)
//	
typedef vector <int_string_pair> map_value_array;

int main(void)
{
    // instances
    //
    
    // value in an arrays
    //	
    map_value_array array;
    
    array.reserve(3);
    array.push_back( make_pair( 1, "one" ) );
    array.push_back( make_pair( 3, "three" ) );	// randomly ordered
    array.push_back( make_pair( 2, "two" ) );
    
    // insert into a map instance
    //	
    mapped_strings mstrs;
    
    copy( array.begin(), array.end(), 
	insert_iterator <mapped_strings> (mstrs, mstrs.end()) );
    
    mapped_strings :: iterator iter = mstrs.begin();
    cerr << iter->first << " " << iter->second << endl; ++ iter;
    cerr << iter->first << " " << iter->second << endl; ++ iter;
    cerr << iter->first << " " << iter->second << endl; ++ iter;
    
    assert( iter == mstrs.end() );
    
    return 0;
}

check out:

http://www.sgi.com/tech/stl/insert_iterator.html

The second parameter is the hint to tell where to start the search for
the appropriate insertion location in the case of map, it would be the
exact insertion point in the case of list for example...

HTH,
Gokhan

^ permalink raw reply	[flat|nested] 5+ messages in thread

* template problems
@ 2002-07-26  2:07 Thomas Maier
  2002-07-26 11:08 ` Gokhan Kisacikoglu
  0 siblings, 1 reply; 5+ messages in thread
From: Thomas Maier @ 2002-07-26  2:07 UTC (permalink / raw)
  To: gcc-help; +Cc: Thomas Maier

[-- Attachment #1: Type: text/plain, Size: 4164 bytes --]

Sorry for reposting, I forgot to attach the file small.cc.

Hi everbody, 

hope this is the right mailing list. I got a problem compiling some C++
code (using "gcc version 2.95.3 20010315 (SuSE)" and also a 3.0 version,
see below).  I do not know if it is valid C++ actually but I guess it
is.  Question is: how can I scope deeper than level one in types used in
templates? :)  Well, if you use a template that gets a container type C
as parameter, you might want to say  "C::value_type some_var;" but in
order to say that you have to use typename:

typename C::value_type some_var;

That's fine.  Now how can I use value_type to "scope one level deeper",
say I want to take the address of some member function of value_type:

void (C::value_type::* some_member_function)();

Just saying

void (typename C::value_type::* some_member_function)();

fails, as does saying

void (typename C::typename value_type::* some_member_function)();

Putting parens just about everywhere did not help, too.  How do I have
to tell g++ to do what I want?  It works in a non-template function:

void f()
{
  {
    map<size_t,string>::mapped_type mt("ext");
    map<size_t,string>::key_type kt(42);
    map<size_t,string>::key_type (map<size_t,string>::mapped_type::* key_method)() const
      = &map<size_t,string>::mapped_type::size;
  }

  {
    typedef map<size_t,string> Cont;
    Cont::mapped_type mt("ext");
    Cont::key_type kt(42);
    Cont::key_type (Cont::mapped_type::* key_method)() const = &Cont::mapped_type::size;
  }
}

The second block is the same as the first one but it uses a typedef to
make things easier to read.  I wrote the first block only to see if the
typedef makes things work.  I attach a small file small.cc that you can
compile.

The problem is:

/*11*/ template <class Container> void
/*12*/ foo(Container& container, void (typename Container::mapped_type::* member_function)())
/*13*/ { }

which gives

g++ -Wall -c small.cc
small.cc:12: parse error before `*'
small.cc:12: `foo' declared as function returning a function


Probably g++ doesn't know that Container::mapped_type is a type.  You
even have to tell it that Container is a type, that's what that typename
is for.  I tried to cheat g++ with writing 

/*16*/ template <class Container, class MappedType = typename Container::mapped_type> void
/*17*/ foo(Container& container, void (MappedType::* member_function)())
/*18*/ { }

but it only said 

small.cc:18: default argument for template parameter in function template `foo(Container &, void (MappedType::*)())'

(Yes, sure it is, doesn't really sound like an error.  Is it one?  In
the Stroustrup there is an example with default arguments so I expected
it to work.) 

I also tried all that with "gcc version 3.0.1 (SuSE)".  Doesn't work. 
Unfortunately I am not able to just download and install the latest gcc
version to see if things work as I only have a very slow dial up
connection (and here in Germany they charge for connection *times*!
pfff...).  And unexperienced as I am that would probably make things
even worse :).  So is this a problem with g++ or with my understanding
of or my way of writing down C++?  And if it is the former, is it fixed
in 3.1 or will it be fixed in 3.2?  And please be so kind and cc any
follow-ups to me as I am not on this list (because of said f!$%&ing slow
modem :). 

Regards and advTHANKSance, Thomas. 



P.S.: Just in case you wonder why the hell I need this: Actually I
wanted to write an assoc_insert_iterator to insert a value into a map
like a back_inserter (gives a back_insert_iterator that) inserts into a
list, for example.  The iterator needs to be parameterized with some X
where it can get the value's key from.  Basically when I write
(simplified pseudo code) 

map<Key, Value> m; 
fill(assoc_inserter(m, X)); 

and fill(assoc_insert_iterator iter) calls iter's operator=, operator=
has to call some method or function "Key X(Value)" that I gave as a
parameter. 

Specifying functions works, see above.  But when I want to pass a method
(exploiting the fact that some classes have some method giving a
key-function) it doesn't, see above.

-- 
Thomas Maier <T.Maier@tu-bs.de>

[-- Attachment #2: small.cc --]
[-- Type: text/x-c, Size: 1023 bytes --]

#include<string>
#include<map>
using namespace std;

// non-member functions work
template <class Container> void
foo(Container& container, void (*function) ())
{ }

// member functions don't
template <class Container> void
foo(Container& container, void (typename Container::mapped_type::* member_function)())
{ }

// also doesn't work
template <class Container, class MappedType = typename Container::mapped_type> void
foo(Container& container, void (MappedType::* member_function)())
{ }

// non-template function using map as container works
void f()
{
  {
    map<size_t,string>::mapped_type mt("ext");
    map<size_t,string>::key_type kt(42);
    map<size_t,string>::key_type (map<size_t,string>::mapped_type::* key_method)() const
      = &map<size_t,string>::mapped_type::size;
  }

  {
    typedef map<size_t,string> Cont;
    Cont::mapped_type mt("ext");
    Cont::key_type kt(42);
    Cont::key_type (Cont::mapped_type::* key_method)() const = &Cont::mapped_type::size;
  }
}

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2002-07-26 23:34 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-07-26  2:02 template problems Thomas Maier
2002-07-26  2:07 Thomas Maier
2002-07-26 11:08 ` Gokhan Kisacikoglu
2002-07-26 15:18   ` Thomas Maier
2002-07-26 16:34     ` Gokhan Kisacikoglu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).