Skip to main content
GameDev.net gamedev.net
🔒 Locked

STL gurus - help needed

Started by Drew_Benton Mar 20, 2005 at 12:37 AM 8 replies 2k views
Original Post
Drew_Benton
Drew_Benton
Ok I have a few questions for all you STL gurus. I am having trouble with a templated map function when I use the [] operator. I did a little research, and it says that I should overload the < operator, but I could not get that to work at all. So after a few hours of trying to figre it out myself, I have decided to ask if anyone has any tips/ideas on what the heck I have to do to get this to work correctly. I made a super slim version of my code to only show what does not work - I deleted out a lot of stuff.

#include <map>

template <class t>
class Test
{
public:
	static std::map <int, Test<t>*> ObjectList;
public:
};

template <class T>
std::map <int, Test<T>*> Test<T>::ObjectList;

class ClassTest : public Test< ClassTest >
{
private:

public:
	ClassTest()
		: Test<ClassTest>()
	{
	}
};

std::map< std::string, ClassTest*> m_List;

int main( int argc, char** argv )
{
	m_List["ClassTest 1"] = new ClassTest;
	m_List["ClassTest 2"] = new ClassTest;
	m_List["ClassTest 3"] = new ClassTest;
	m_List["ClassTest 4"] = new ClassTest;
	m_List["ClassTest 5"] = new ClassTest;
	return 0;
}




The errors only happen when I use the [] operator on m_List. The error readout I get is:

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2676: binary '<' : 'const std::string' does not define this operator or a conversion to a type acceptable to the predefined operator

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'const std::string'

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'const std::string'

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xtree(1170) : see declaration of 'std::operator`<''

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'const std::string'

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xtree(1170) : see declaration of 'std::operator`<''

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)' : could not deduce template argument for 'const std::pair<_Ty1,_Ty2> &' from 'const std::string'

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\utility(73) : see declaration of 'std::operator`<''

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)' : could not deduce template argument for 'const std::pair<_Ty1,_Ty2> &' from 'const std::string'

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\utility(73) : see declaration of 'std::operator`<''

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)' : could not deduce template argument for 'const std::pair<_Ty1,_Ty2> &' from 'const std::string'

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\utility(73) : see declaration of 'std::operator`<''
f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const std::string'

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xutility(655) : see declaration of 'std::operator`<''

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const std::string'

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xutility(655) : see declaration of 'std::operator`<''

f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139): error C2784: 'bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const std::string'
        
f:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xutility(655) : see declaration of 'std::operator`<''





Second question - does anyone know why on this reference to STL map, std::map does not work correctly? If I try that way it says that it does not take 3 arguments - in my compiler it shows that it takes 4, none of which are a function address. Third Question - how the heck do I return a iterator?! I tried using:

std::map <int, Test<t>*>::iterator GetItr()
{
   return ObjectList.begin();
}
And that does not work. It alwasy says that error C2146: syntax error : missing ';' before identifier 'GetItr'. Is there any way that you can return a specific iterator like that. I tried looking into the std::iterator class but I can't figure out the ump-teen arguments it takes between the < and >'s. Thanks for any help in advanced! I will be checking back in like 9 hours or so.
Desert Fox
Desert Fox
1: #include That should be all you need, as string provides an operator <
2: map does take 4 parameters; the third one is the one you want, it defaults to std::less. In general it's better to provide your own specialization of std::less or write your own comparison function object than overloading the < operator (though not always)

3:
 typename std::map<int, Test<t>*>::iterator GetIter(){    return ObjectList.begin();}


typename is important when dealing with accessing dependent types in templated classes. Without it the compiler basically assumes that what you're referencing is an identifier and not a type
"Is life so dear, or peace so sweet, as to be purchased at the price of chains and slavery?" - Patrick Henry
snk_kid
snk_kid
Quote:
Original post by Drew_Benton
in my compiler it shows that it takes 4, none of which are a function address.


Yes because it takes comparator (binary predicate) type this allows its to be used with any C++ callable entity meaning anything that supports "()" if it used nontype parameter which was a pointer to function that would be very restricting and only allow free-functions to be used which is not very generic.

The last type parameter and generally the case for all standard library containers is the allocator type (which defaults to using std::allocator) so you can provide custom allocation schemes.

Quote:
Original post by Desert Fox
In general it's better to provide your own specialization of std::less


The standard allows user (partial) specializations in namespace std meaning you can open up namespace std for (partial) specializations but its not a good idea to change the meaning of std::less it has a specific meaning, better to provide a custom comparator instead.

[Edited by - snk_kid on March 20, 2005 4:42:44 AM]
Drew_Benton
Drew_Benton
Quote:
Original post by Desert Fox
1: #include That should be all you need, as string provides an operator <


OMG! I feel so dumb now. Can't believe I totally missed that. I was trying to define own operator and everything with string and vectors. [lol]

Quote:

2: map does take 4 parameters; the third one is the one you want, it defaults to std::less. In general it's better to provide your own specialization of std::less or write your own comparison function object than overloading the < operator (though not always)


Ok cool thanks. I will look into that class. I am still learning STL, so I didn't know it didn't use the regular operator overloads

Quote:

3:
 typename std::map<int, Test<t>*>::iterator GetIter(){    return ObjectList.begin();}


typename is important when dealing with accessing dependent types in templated classes. Without it the compiler basically assumes that what you're referencing is an identifier and not a type


Wow, thanks again. Works perfect. I will definitly need to learn what typename does. I think I had tried typedef but that did not work correctly, probabalyl because I did not use it correctly. Thanks again! Everything works great, just to stomp out a few logical bugs now...

Quote:
Original post by snk_kid
Yes because it takes comparator (binary predicate) type this allows its to be used with any C++ callable entity meaning anything that supports "()" if it used nontype parameter which was a pointer to function that would be very restricting and only allow free-functions to be used which is not very generic.

The last type parameter and generally the case for all standard library containers is the allocator type (which defaults to using std::allocator) so you can provide custom allocation schemes.


Awesome. I was wondering how I used those last two correctly. Even though I think the code compiles now, I will definitly do some more looking into using those last parameters for my own custom classes and such from now on for more flexibility in my designs.

Quote:
The standard allows user (partial) specializations in namespace std meaning you can open up namespace std for (partial) specializations but its not a good idea to change the meaning of std::less it has a specific meaning, better to provide a custom comparator instead.


Ok cool, thanks for that as well. I have never heard "custom comparator" so I will find some information on it with google. I will try to use that wayas well, don't want to bork by STL classes anymore then I already have.

Ok a big THANKS to both of you. Phew, I don't think I could have done it with out you [smile]. I guess I need to go ahead and move buying that big STL reference book to the top of my priority list. The online tutorials just aren't cutting it now [wink]. Thanks again!

- Drew
bkt
bkt
I think I agree; I will definately be buying that book ;)
-John "bKT" Bellone [homepage] [[email=j.bellone@flipsidesoftware.com]email[/email]]
snk_kid
snk_kid
Quote:
Original post by Drew_Benton
I think I had tried typedef but that did not work correctly, probabalyl because I did not use it correctly.


Its the same for nested typedefs you need to use typename, rule of thumb if a type depends on a template type parameter and you need to refer to nested types thats when to use typename otherwise the compilers defaults into thinking your referring to a static member (i don't know if that made any sense [rolleyes]) for example:

template < typename Tp > struct foo { typedef Tp value_type; };template < typename Tp >struct bar {    typedef typename foo<Tp>::value_type value_type;};


foo has type dependence on the template type parameter Tp or:

#include <iterator>template < typename InputIterators >void foo(InputIterators beg, InputIterators end) {   // iterator_traits nested value_type type is dependant   // on the template type parameter *InputIterators* which isn't known   // until template instantion.   typedef typename std::iterator_traits<InputIterators>::value_type val_t;  .....}


Quote:
Original post by Drew_Benton
Awesome. I was wondering how I used those last two correctly. Even though I think the code compiles now.


Yeah as mentioned for std:::map its comparator type defaults to use std::less and allocator type to std::allocator.

Quote:
Original post by Drew_Benton
Ok cool, thanks for that as well. I have never heard "custom comparator" so I will find some information on it with google. I will try to use that wayas well, don't want to bork by STL classes anymore then I already have.


For std::basic_string (and type alias std::string) you don't need one as std::less uses the less than operator which for std::basic_string is already defined.

When i said custom comparator i didn't know what else to call it, i thought it may have been obvious calling it that way so i wouldn't have to go into to much detail that may have been off-topic.

Basically what i mean't if not overloading the relational less than operator then instead declare & define your own comparisons routine either free/member-function or functor instead of changing what std::less means because say for example you made a full-specialization for some pointer type for one container such that it imposes an ordering based on some criteria other than memory addresses but later on you need another ordered container based on ordering of memory addresses (that is valid in some contexts). That might be okay for one person but pretty bad for a team or even community of people, see what i'm saying?

To be specific STL have a set of *Concepts* that imposes a set of requirements on a type or group of types, for instance std:map's third type parameter the type must be a model of the STL concept Strict Weak Ordering

which is a refinement of the concept Binary Predicate

which is a refinement of the concept Binary Function

which is a refinement of the concept Assignable

That could be anything not just a free-function.

Don't worry it doesn't effect code other than if your type doesn't support one of the requirements of a concept either your compiler wont compile your code [smile], if compileable then your code has undefined behaviour, or your program will be in an undefined state at runtime. It all depends on the requirement.

There are some concept requirements that are beyond the compiler this when concept checking and constraints comes into the picture to help the compiler stop your code from being compiled and being put into an undefined state but its abit beyond scope of this thread, this is generic programming stuff.

[Edited by - snk_kid on March 20, 2005 11:31:53 AM]
Drew_Benton
Drew_Benton
Awesome! Thanks for the additional information man.

Quote:
When i said custom comparator i didn't know what else to call it, i thought it may have been obvious calling it that way so i wouldn't have to go into to much detail that may have been off-topic.


Oh no, that was great. What I meant was that I never heard of comparator in the first place [wink]. I typed it in google and found some stuff, so I knew what you had meant, no worries.

Thanks for the additonal explanation of typename. What's funny is that the only place I've seen them used before is as substitues for typedef in some example a while back. I always had the notion it was not that important - for I never saw it used. What you said makes perfect sense. I am following you [smile].

More links! I will start looking at those references as well. It's weird when you are smoothly sailing along then all of a sudden, you encounter some stuff you've never seen before. At least I don't have to wander the dark [grin]. Thanks again for your help. I will bve making a post later on with what has came out of all this stuff. [wink]

- Drew
snk_kid
snk_kid
You might want to re-read that bit again because i made some mistakes and added bits and pieces [smile]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.