Boost logo

Boost Users :

From: Joaquín Mª López Muñoz (joaquin_at_[hidden])
Date: 2007-02-02 09:57:04


Hello Markus,

Markus Werle ha escrito:

> > Hi!
>
> I tried to use multi_index_container as a drop in replacement
> for std::map and hoped that I could obtain non-const references
> to the values therein.
>
> Although returning a non-const reference might not be a problem for
> a multi_index_container with only 1 sorting criterium the lib
> and the compiler insist on const &. Workarounds beyond modify(...) available?

(First of all, your statement
        element & ref = test.find("a");
is incorrect in that it's missing an indirection. I assume your intended code is
        element & ref = *test.find("a");
although it doesn't compile either because of the const & issue you complain
about.)

B.MI always returns const references to the elements so as to not allow
the user to modify the keys on her own. This has nothing to do with whether
the number of indices is one or more, so I don't quite get your reasoning.
If we could get a non-const reference the following violation of the internal
invariants of B.MI would pass at compile time:
        element & ref = test.find("a");
        ref.get<0>()="b"; // boom
So, in order to get non-const access to the second member of your tuple
(as the first must be kept untouched since it's a key), you've got to somehow
circumvent this protective measure. There are several alternatives.

1. Use const_cast to eliminate constness
        const element & ref = *test.find("a");
        std::string & s = const_cast<std::string &>(ref.get<1>());
This is dangerous but safe if you know what you're doing --i.e. you don't
touch keys.

2. You can have a drop-in replacement for std::map if only you use
a special type of pair-like element instead of a tuple, the details are
given at http://tinyurl.com/337bvp .

3. You can keep using boost::tuples as your element types and
also gain non-const access to selected elements by taking advantage
of a facility provided by Boost.Tuple called access traits, see
"Traits classes for tuple element types" at
http://boost.org/libs/tuple/doc/tuple_advanced_interface.html

        // object wrapper granting non-const access under const
        // conditions
        template<typename T>
        class mutable_tuple_element
        {
        public:
                mutable_tuple_element(const T& t):t(t){}
                operator T&()const{return t;}
        private:
                mutable T t;
        };

        // plug mutable_tuple_element into Boost.Tuple access
        // traits system
        namespace boost{

        namespace tuples{

        template<typename T>
        class access_traits<mutable_tuple_element<T> >
        {
                typedef T& non_const_type;
                typedef T& const_type;
                typedef const T& parameter_type;
        };

        } // namespace tuples

        } // namespace boost

        // define now your element type as follows:

        typedef boost::tuple<
                std::string, mutable_tuple_element<std::string> > element;

This allows you then to write:
        const element & ref = *test.find("a");
        std::string & s = ref.get<1>(); // OK
but does not allow this
        const element & ref = *test.find("a");
        std::string & s = ref.get<0>(); // compile error
which is perfect, since we don't want to change key elements.
Complete code snippet attached.

Hope this helps,

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo




Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net