9

C++ references tells us for a std::map

typedef pair<const Key, T> value_type;

Is it possible to force the Key Type not to be const ? I need to do this in a template method like

template<class T> // T represent a map in general (std::map, boost::unordered_map or whatever..)
void foo(const T& m)
{
  typename T::value_type::first_type x;
  x=0; // Wrong because x is const ...
}
Guillaume Thomas
  • 2,220
  • 2
  • 24
  • 33

4 Answers4

18

No, it's not.

This is because map performs its internal ordering based on key. If you could modify the key yourself, willy-nilly, all hell would break loose.

You should use the provided API functions; where the use of one results in changing a Key value (actually I don't think that any do), the appropriate internal re-ordering may take place.

Think of getters and setters, and their use in providing an alternative to messy/dangerous direct member access.


However, you could write this:

template<class T>
void foo(const T& m)
{
   typename T::key_type x;
   x = 0;
}

std::map type aliases

key_type                Key
mapped_type             T
value_type              pair<const Key,T>
key_compare             Compare
value_compare           Nested class to compare elements
allocator_type          Allocator
reference               Allocator::reference
const_reference         Allocator::const_reference
iterator                Bidirectional iterator
const_iterator          Constant bidirectional iterator
size_type               Unsigned integral type (usually same as size_t)
difference_type         Signed integral type (usually same as ptrdiff_t)
pointer                 Allocator::pointer
const_pointer           Allocator::const_pointer
reverse_iterator        reverse_iterator<iterator>
const_reverse_iterator  reverse_iterator<const_iterator>
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    For information, Boost.MultiIndex offers the `update` method which allows one to change a given object (in place) and then correctly reposition it in all the indexes. This is, obviously, much more advanced than STL map/unordered_map :) – Matthieu M. Jul 21 '11 at 09:19
5

typename T::key_type will give you the key type without adding a const qualifier.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
4

Previous answers should be sufficient for your simple question. As a more general approach, you may use boost::remove_const (from boost type_traits) to remove const qualifier to a type.

template<class T> // T represent a map in general (std::map, boost::unordered_map or whatever..)
void foo(const T& m)
{
  typedef typename T::value_type::first_type X; //is const
  typedef typename boost::remove_const<X>::type NonConstX;
  NonConstX x;
  x=0; 
}
Benoît
  • 16,798
  • 8
  • 46
  • 66
0

The key type must be const. If you're certain that you won't change the ordering of the map you can cast away the const-ness of iterators. If you're mistaken this can lead to ugly bugs though.

Jay
  • 13,803
  • 4
  • 42
  • 69
  • Sorry Dennis, it's quite valid to do this if you use map to order instantiated objects by a member of the object. If you don't change that member then you haven't changed the order. A completely immutable container isn't a very useful tool. – Jay Jul 22 '11 at 16:48
  • Nope. The map stores `pair` objects. Note that the key is stored in a const object. Modifying a const object, no matter why it is used elsewhere, is undefined behavior. If the member is mutable, and it does not effect the ordering, you might be okay, but that's a pretty rare occurrence. – Dennis Zickefoose Jul 22 '11 at 18:23
  • It works fine if the portion of the key that determines ordering is not changed. You can still change other members of the key object's instance that do not change the order. – Jay Jul 22 '11 at 18:47
  • 1
    It is undefined behavior. It might appear to work, but that does not make it safe. – Dennis Zickefoose Jul 22 '11 at 19:13