C++ & operator []=
by Matthew Wilson

Listing One
// Alternative op [] semantics, via argument decoration
template<class T>
struct inserter
{
  inserter(T const &arg)
    : argument(arg)
  {}
  T const &argument;
};

// "maker" function
template<class T>
inline inserter<T> insert(T const &arg)
{
  return inserter<T>(arg);
}
template< typename K // Key type
        , typename R // Reference type
        , . . .
        >
class umap
{
  . . .
  // Some "standard" map methods, used in the new ones below
  std::pair<iterator, bool> insert(value_type const &value);
  iterator                  find(key_type const &key);
  const_iterator            find(key_type const &key) const;

  /// This method looks up the value for the given key
  /// \note This does <b>not</b> perform insertions
  referent_type const &operator [](key_type const &key) const
  {
    const_iterator  it  = this->find(key);
    if(this->end() == it)
    {
      throw new std::out_of_range("invalid key");
    }
    return (*it).second;
  }
  /// This method looks up the value for the given key
  /// \note This does <b>not</b> perform insertions
  referent_type   &operator [](key_type const &key)
  {
    iterator  it  = this->find(key);

    if(this->end() == it)
    {
      throw new std::out_of_range("invalid key");
    }
    return (*it).second;
  }
  /// Specialised override which performs insertions
  template<class T1>
  referent_type   &operator [](inserter<T1> const &key)
  {
    // How's this for a nice little statement ... ?? ;-)
    return (*this->insert(key.argument).first).second;
  }
  . . .
};

Listing Two

// An unambiguous map: implemented in terms of std::map
  . . . // All the inserter / insert() stuff from Listing 1
template< typename K                     // Key type
        , typename R                     // Reference type
        , typename P = std::less<K>      // Comparison predicate
        , typename A = std::allocator<T> // Allocator
        >
class umap // unambiguous map. Not too cheeky, eh?
{
/// \name Types
/// @{
private:
  typedef std::map<K, T, P, A>                    map_impl_type;
public:
  typedef typename map_impl_type::key_type        key_type;
  typedef typename map_impl_type::referent_type   referent_type;
  typedef typename map_impl_type::key_compare     key_compare;
  typedef typename map_impl_type::allocator_type  allocator_type;
  typedef typename map_impl_type::value_type      value_type;
  typedef typename map_impl_type::value_compare   value_compare;
  typedef umap<K, T, P, A>                        class_type;
  typedef typename map_impl_type::size_type       size_type;
  typedef typename map_impl_type::difference_type difference_type;
  typedef typename map_impl_type::reference       reference;
  typedef typename map_impl_type::const_reference const_reference;
  typedef typename map_impl_type::iterator        iterator;
  typedef typename map_impl_type::const_iterator  const_iterator;
  typedef typename map_impl_type::reverse_iterator reverse_iterator;
  typedef typename map_impl_type::const_reverse_iterator  
                                             const_reverse_iterator;
/// @}
/// \name Construction
/// @{
public:
  explicit umap(key_compare const     &pred = key_compare()
              , allocator_type const  &ator = allocator_type())
    : m_map(pred, ator)
  {}
  umap(class_type const &rhs)
    : m_map(rhs.m_map)
  {}
#ifdef __STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  template <typename I>
  umap(I from, I to
#else /* ? __STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  umap( value_type const *from, value_type const *to
#endif /* __STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
      , key_compare const &pred = key_compare()
      , allocator_type const &ator = allocator_type())
    : m_map(from, to, pred, ator)
  {}
/// @}
/// \name Member access and keyed-insertion operations
/// @{
  /// This method looks up the value for the given key
  /// \note This does <b>not</b> perform insertions
  referent_type const &operator [](key_type const &key) const
  {
    const_iterator  it  = m_map.find(key);
    if(m_map.end() == it)
    {
      throw new std::out_of_range("invalid key");
    }
    return (*it).second;
  }
  /// This method looks up the value for the given key
  /// \note This does <b>not</b> perform insertions
  referent_type   &operator [](key_type const &key)
  {
    iterator  it  = m_map.find(key);
    if(m_map.end() == it)
    {
      throw new std::out_of_range("invalid key");
    }
    return (*it).second;
  }
  /// Specialised override which performs insertions
  template<class T1>
  referent_type   &operator [](inserter<T1> const &key)
  {
    return m_map[key.argument];
  }
  referent_type       &at(key_type const &key)
  {
    return operator [](key);
  }
  referent_type const &at(key_type const &key) const
  {
    return operator [](key);
  }
  std::pair<iterator, ss_bool_t>  insert(value_type const &value)
  {
    return m_map.insert(value);
  }
  iterator                insert(iterator it, value_type const &value)
  {
    return m_map.insert(it, value);
  }
#ifdef __STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  template <typename I>
  void insert(I from, I to)
#else /* ? __STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  void insert(value_type const *from, value_type const *to)
#endif /* __STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  {
    return m_map.insert(from, to)
  }
/// @}
  // All of the rest of the methods forward directly to m_map
/// \name Operations
/// @{
public:
  iterator  erase(iterator it)
  {
    return m_map.erase(it);
  }
  iterator  erase(iterator first, iterator last);
  size_type erase(key_type const &key);
  void      clear();
  void      swap(class_type const &rhs);
/// @}
/// \name Attributes
/// @{
public:
  size_type       size() const
  {
    return m_map.size();
  }
  size_type       max_size() const;
  bool            empty() const;
  allocator_type  get_allocator() const;
  key_compare     key_comp() const
  value_compare   value_comp() const;
/// @}
/// \name Searching
/// @{
public:
  iterator                                  find(key_type const &key)
  {
    return m_map.find(key);
  }
  const_iterator                 find(key_type const &key) const;
  size_type                      count(key_type const &key) const;
  iterator                       lower_bound(key_type const &key);
  const_iterator                 lower_bound(key_type const &key) const;
  iterator                       upper_bound(key_type const &key);
  const_iterator                 upper_bound(key_type const &key) const;
  std::pair<iterator, iterator>  equal_range(key_type const &key);
  std::pair<const_iterator, const_iterator> 
                              equal_range(key_type const &key) const;
/// @}
/// \name Iteration
/// @{
public:
  iterator                begin();
  iterator                end();
  const_iterator          begin() const;
  const_iterator          end() const;
  reverse_iterator        rbegin();
  reverse_iterator        rend();
  const_reverse_iterator  rbegin() const;
  const_reverse_iterator  rend() const;
  {
    return m_map.rend();
  }
/// @}
private:
  map_impl_type m_map;
};


Listing Three

// An unambiguous map: a veneer over std::map
  . . . // All the inserter / insert() stuff from Listing 1
template< typename K                     // Key type
        , typename R                     // Reference type
        , typename P = std::less<K>      // Comparison predicate
        , typename A = std::allocator<T> // Allocator
        >
class umap
  : public std::map<K, R, P, A> // Inherits publicly
{
/// \name Types
/// @{
private:
  typedef std::map<K, T, P, A>                       parent_class_type;
public:
  typedef typename parent_class_type::key_type       key_type;
  typedef typename parent_class_type::referent_type  referent_type;
  typedef typename parent_class_type::key_compare    key_compare;
  typedef typename parent_class_type::allocator_type allocator_type;
  typedef typename parent_class_type::value_type     value_type;
  typedef typename parent_class_type::value_compare  value_compare;
  typedef umap<K, T, P, A>                           class_type;
  typedef typename parent_class_type::size_type      size_type;
  typedef typename parent_class_type::difference_type difference_type;
  typedef typename parent_class_type::reference       reference;
  typedef typename parent_class_type::const_reference const_reference;
  typedef typename parent_class_type::iterator        iterator;
  typedef typename parent_class_type::const_iterator  const_iterator;
  typedef typename parent_class_type::reverse_iterator reverse_iterator;
  typedef typename parent_class_type:
             :const_reverse_iterator  const_reverse_iterator;
/// @}
/// \name Construction
/// @{
public:
  explicit umap(key_compare const     &pred = key_compare()
              , allocator_type const  &ator = allocator_type())
    : parent_class_type(pred, ator)
  {}
  umap(class_type const &rhs)
    : parent_class_type(rhs)
  {}
  template <typename I>
  umap( I from, I to
      , key_compare const &pred = key_compare()
      , allocator_type const &ator = allocator_type())
    : parent_class_type(from, to, pred, ator)
  {}
/// @}

/// \name Member access and keyed-insertion operations
/// @{
  /// This method looks up the value for the given key
  /// \note This does <b>not</b> perform insertions
  referent_type const &operator [](key_type const &key) const
  {
    const_iterator  it  = this->find(key);
    if(this->end() == it)
    {
      throw new std::out_of_range("invalid key");
    }
    return (*it).second;
  }
  /// This method looks up the value for the given key
  ///
  /// \note This does <b>not</b> perform insertions
  referent_type   &operator [](key_type const &key)
  {
    iterator  it  = this->find(key);

    if(this->end() == it)
    {
      throw new std::out_of_range("invalid key");
    }
    return (*it).second;
  }
  /// Specialised override which performs insertions
  template<class T1>
  referent_type   &operator [](inserter<T1> const &key)
  {
    // How's this for a nice little statement ... ?? ;-)
    return parent_class_type::operator [](key.argument);
  }
  referent_type       &at(key_type const &key)
  {
    return operator [](key);
  }
  referent_type const &at(key_type const &key) const
  {
    return operator [](key);
  }
  // All other methods are visible by inheritance from the veneer
  // base class.
};





7


