6

I'd like to use std::tm () as the key for an std::map-container. But when I try to compile it, I get a lot(10) of errors.

For example:

1.

error C2784: 'bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'const tm' c:\program files (x86)\microsoft visual studio 10.0\vc\include\xfunctional 125

2.

error C2784: 'bool std::operator <(const _Elem *,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const _Elem *' from 'const tm' c:\program files (x86)\microsoft visual studio 10.0\vc\include\xfunctional 125

3.

error C2784: 'bool std::operator <(const std::vector<_Ty,_Ax> &,const std::vector<_Ty,_Ax> &)' : could not deduce template argument for 'const std::vector<_Ty,_Ax> &' from 'const tm' c:\program files (x86)\microsoft visual studio 10.0\vc\include\xfunctional 125

Does all this mean, that I "simply" have to created an function object which compares two std::tm, because there is no standard-comparison defined for this? Or is there another trick? (or may it even be impossible to me? ^^)

Code:

#include <map>
#include <ctime>
#include <string>


int main()
{
    std::map<std::tm, std::string> mapItem;
    std::tm TM;

    mapItem[TM] = std::string("test");
    return 0;
};
Anthony
  • 12,177
  • 9
  • 69
  • 105
Juarrow
  • 2,232
  • 5
  • 42
  • 61

4 Answers4

9

std::map uses a comparer to check if the key already exists or not. So when you use std::tm , you've to provide a comparer as third argument as well.

template < class Key, class T, class Compare = less<Key>,
           class Allocator = allocator<pair<const Key,T> > > class map

So a solution would be functor (as you already guessed):

struct tm_comparer
{
   bool operator () (const std::tm & t1, const std::tm & t2) const
   {           //^^ note this

        //compare t1 and t2, and return true/false
   }
};

std::map<std::tm, std::string, tm_comparer> mapItem;
                             //^^^^^^^^^^ pass the comparer!

Or define a free function (operator <) as:

bool operator < (const std::tm & t1, const std::tm & t2)
{          // ^ note this. Now its less than operator

    //compare t1 and t2, and return true/false
};

std::map<std::tm, std::string> mapItem; //no need to pass any argument now!
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • If I would switch to and unordered_map ,would it make this obsolete? – Juarrow May 12 '11 at 14:12
  • @Incubbus: No. `unordered_map` would still need it. Because both type of map needs to check the keys. They must check for *unique* keys. – Nawaz May 12 '11 at 14:15
  • http://pastebin.com/v1X6tai9 <- does this functor look sufficient enough, if we presume, that someone needs a few seconds to enter stuff (so tm_sec should never be the same)? – Juarrow May 12 '11 at 14:32
  • @Incubbus: why can't `tm_sec` be same? `01:30:05` and `03:49:05` both has same `tm_sec`. What you probably can do is, convert `tm` into number of seconds, and compare only the second. Or if you fear that value would exceed the maximum value of the datatype (`int`, `long long` or whatever you take), then you can convert `tm` into number of `hours`, and `seconds`. For example, `5 days, 4 hours, 30 minutes, 7 seconds` would become : `(5 x 24 + 4)` hours and `30 x 60 + 7` seconds. If you do so, then it would be easy to compare. – Nawaz May 12 '11 at 15:07
  • @Incubbus: Also, you need to write constructor and destructor in the comparer functor, as the default ones generated by the compiler is enough for you. – Nawaz May 12 '11 at 15:08
  • What I intended was: my tm_sec is compared last, so I can ensure that year, day, minute, hour are the same... the other thing you suggested: this method would be equal to saving the value returned by time(NULL);... i thought it would be easier to handle a ready-converted tm-structure... but as it turned out a few minutes ago: I still have a problem while using this functor and calling find() on the map... there is an runtime error saying: invalid operator – Juarrow May 12 '11 at 15:36
  • @Incubbus: I didn't get what problem you're facing now, and what current implementation you're using now. Can you give me these details? – Nawaz May 12 '11 at 15:58
  • when my code reaches `std::map::iterator it = m_mapItem.find(Item.GetDate());` it throws an runtime error saying `Expression: invalid operator <` in an include file called xtree (I think it has to do with searching mechanism of the map) – Juarrow May 12 '11 at 19:28
  • The free function is illegal, I think, as you're supposed to add only overloads for functions and operators where at least one of the arguments is a UDT outside `namespace std`. Besides, you'd have issues finding it. Name lookup wouldn't look in the global namespace, since neither the caller (std::map) nor the arguments (std::tm) are in the global namespace. – MSalters May 13 '11 at 08:34
  • if found the problem after examining the STL-code... It seems that my function needs to return false in the last spot; at least it makes it work and works correctly after i done some tests – Juarrow May 13 '11 at 23:50
2

Yes std::tm doesn't define a < operator.

Andreas Brinck
  • 51,293
  • 14
  • 84
  • 114
2

A free function suffices, you do not need a function object.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
2

Yes, you need to define operator< for tm structure. see http://www.cplusplus.com/reference/stl/map/map/ for example (bottom of page).

barbacan
  • 632
  • 6
  • 16