Question

I have set up a Windows C++ Visual Studio project (VS9) to test the use of Boost::Multi_Index. The container is being set up to store shared pointers to a custom object, FC::ClientOrder. For testing, the object is very simple, storing only a string and a char variable. Boost version is 1_46_0

I have configured the Multi_Index container to index on the shared pointer as the identity, and to also index on the two member variables, using member functions to access. That seems fine and works well.

I am having a problem with the modify() method though. I realise I have to use modify() if I want to update any member variables that are part of an index. I also realise that I have to locate the FC::ClientOrder object in the container first using find(), and then pass the iterator to modify() to make the change.

If I find the FC::ClientOrder shared pointer via the identity, the shared pointer itself, everything works well, and modify() is happy.

If I find the FC::ClientOrder shared pointer via the member function, clOrdID() (essentially looking up the order on it's ID, very common usage) then the modify() function fails, even though the syntax is identical. I get a compiler error, which seems to indicate a type issue, but I am finding it hard to understand what is wrong.

Will modify() only work with an iterator based on the identity index? If so, to edit the order via it's clOrdID, I would have to do two lookups, one to find the order in the container (and get it's spOrder variable) and one to then create an iterator based on the spOrder value. That seems to defeat the object of being able to pull up the order via the clOrdID() value.

I think I have misunderstood what the modify() function requires. For now, I can work around this by using the double lookup, but if anyone has a solution, I would greatly appreciate it. I am pretty new to Functors so maybe I have misunderstood what modify() needs.

Thanks in advance for any help, it will be greatly appreciated. Sample code chunks should follow...

///////////////////////////////////////////////////////////////////////////////
// FILE #1: FCClientOrder.h
///////////////////////////////////////////////////////////////////////////////

#ifndef FCClientOrder_H
#define FCClientOrder_H

#include <string>                                                               // Changed to use std::string

////////////////////////////////////////////////////////////////////////////////
// ClientOrder v3: RAM definition of a market order - stripped out for testing

namespace FC
{

class ClientOrder
{
public:


    ClientOrder();                                                              // Default Ctor

    virtual ~ClientOrder();                                                     // Dtor


    //////////////////////
    // ACCESSOR FUNCTIONS

    std::string clOrdID(void) const;                                            // Get
    void clOrdID(const std::string& sClOrdID);                                  // Set

    char ordStatus(void) const;                                                 // Get
    void ordStatus(char cOrdStatus);                                            // Set


    ///////////////////
    // PUBLIC STATICS

    static void change_status_static(std::tr1::shared_ptr<FC::ClientOrder> spOrder,char cOrdStatus);    // Static method to change status

    // Functor
    struct change_status_by_sp
    {
        change_status_by_sp(char cOrdStatus)                                            // Ctor
        :   _cOrdStatus( cOrdStatus )
        {}

        void operator()(std::tr1::shared_ptr<FC::ClientOrder> spOrder)          // Functor
        { spOrder->ordStatus( _cOrdStatus ); }

    private:
        char _cOrdStatus;
    };


private:

    ////////////////////
    // PRIVATE MEMBERS

    std::string                 m_sClOrdID;                                     // Client order ID
    char                        m_cOrdStatus;                                   // Order Status

}; // end of class ClientOrder

} // end of namespace FC

#endif // FCClientOrder_H




///////////////////////////////////////////////////////////////////////////////
// FILE #2: FCClientOrder.cpp
///////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FCClientOrder.h"

namespace FC
{

    ClientOrder::ClientOrder()
    { ordStatus( '0' ); }

    ClientOrder::~ClientOrder()                                                     // Dtor
    {}

    ///////////////////////////////////////////////////////////////////////////
    // PUBLIC FUNCTIONS
    //

    void ClientOrder::change_status_static(std::tr1::shared_ptr<FC::ClientOrder> spOrder,char cOrdStatus)
    { spOrder->ordStatus( cOrdStatus ); }


    ///////////////////////////////////////////////////////////////////////////
    // GET/SET FUNCTIONS
    //

    std::string ClientOrder::clOrdID(void) const                                // Get Client Order ID
    { return m_sClOrdID; }
    void ClientOrder::clOrdID(const std::string& sClOrdID)
    { m_sClOrdID = sClOrdID; }

    char ClientOrder::ordStatus(void) const
    { return m_cOrdStatus; }
    void ClientOrder::ordStatus(char cOrdStatus)
    { m_cOrdStatus = cOrdStatus; }

} // end of namespace FC





///////////////////////////////////////////////////////////////////////////////
// FILE #3: MIC Definition, and member declaration
///////////////////////////////////////////////////////////////////////////////

    typedef std::tr1::shared_ptr<FC::ClientOrder>           spClientOrder;
    typedef boost::multi_index::multi_index_container
    <
        spClientOrder,                                                      // Contained type, shared pointer to ClientOrder
        boost::multi_index::indexed_by
        <
            boost::multi_index::ordered_unique                              // 0 index - shared pointer index
            <
                boost::multi_index::identity<spClientOrder>,
                std::less<spClientOrder>
            > ,
            boost::multi_index::ordered_unique                              // 1 index - ClientOrderID
            <
                boost::multi_index::const_mem_fun< FC::ClientOrder, std::string, &FC::ClientOrder::clOrdID >
            > ,
            boost::multi_index::ordered_non_unique                          // 2 index - Order Status
            <
                boost::multi_index::const_mem_fun< FC::ClientOrder, char, &FC::ClientOrder::ordStatus > ,
                std::less<char>
            > 
        >
    > OrderMIC;





    // Member in working class
    OrderMic        m_micOrders;






///////////////////////////////////////////////////////////////////////////////
// FILE #4: Utility Functions to update the MIC via .modify()
///////////////////////////////////////////////////////////////////////////////

    bool XMLTestApp::updateOrder(spClientOrder spOrder,char cOrdStatus)                 // Order Status is an index, so you must modify via MIC member functions
    {
        OrderMIC::nth_index<0>::type& index = m_micOrders.get<0>();
        OrderMIC::nth_index<0>::type::iterator i = index.find( spOrder );
        OrderMIC::nth_index<0>::type::iterator iEnd = index.end();
        if ( i != iEnd )
        {
            // FOUND
            // i points at the order to change
            return m_micOrders.modify(i,FC::ClientOrder::change_status_by_sp(cOrdStatus));
        }

        return false;
    }


    bool XMLTestApp::updateOrder(const std::string& sClOrdID,char cOrdStatus)                   // Order Status is an index, so you must modify via MIC member functions
    {
        OrderMIC::nth_index<1>::type& index = m_micOrders.get<1>();
        OrderMIC::nth_index<1>::type::iterator i = index.find( sClOrdID );
        OrderMIC::nth_index<1>::type::iterator iEnd = index.end();
        if ( i != iEnd )
        {
            // FOUND

            // Option1 - This works, but does another lookup via alternative fn
            return updateOrder( *i,cOrdStatus );                                                // <- Works

            // Option2 - Attempt to use static fn, fails
            //spClientOrder spOrder = *i;
            //return m_micOrders.modify(i,FC::ClientOrder::change_status_static(spOrder,cOrdStatus));

            // Option3 - Attempt to use *i as spOrder, fails
            //return m_micOrders.modify(i,FC::ClientOrder::change_status_by_sp(cOrdStatus));
        }

        return false;
    }




// FILE #5: Compile Error

1>------ Build started: Project: XMLTest, Configuration: Debug Win32 ------
1>Compiling...
1>XMLTestApp.cpp
1>c:\program files\microsoft visual studio\myprojects\xmltest\xmltest\xmltestapp.cpp(931) : error C2664: 'bool boost::multi_index::detail::ordered_index<KeyFromValue,Compare,SuperMeta,TagList,Category>::modify<FC::ClientOrder::change_status_by_sp>(boost::multi_index::detail::bidir_node_iterator<Node>,Modifier)' : cannot convert parameter 1 from 'boost::multi_index::detail::bidir_node_iterator<Node>' to 'boost::multi_index::detail::bidir_node_iterator<Node>'
1>        with
1>        [
1>            KeyFromValue=boost::multi_index::identity<FC::XMLTestApp::spClientOrder>,
1>            Compare=std::less<FC::XMLTestApp::spClientOrder>,
1>            SuperMeta=boost::multi_index::detail::nth_layer<1,FC::XMLTestApp::spClientOrder,boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<FC::XMLTestApp::spClientOrder>,std::less<FC::XMLTestApp::spClientOrder>>,boost::multi_index::ordered_unique<boost::multi_index::const_mem_fun<FC::ClientOrder,std::string,::>>,boost::multi_index::ordered_non_unique<boost::multi_index::const_mem_fun<FC::ClientOrder,char,::;>,std::less<char>>>,std::allocator<FC::XMLTestApp::spClientOrder>>,
1>            TagList=boost::mpl::vector0<boost::mpl::na>,
1>            Category=boost::multi_index::detail::ordered_unique_tag,
1>            Node=boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<FC::XMLTestApp::spClientOrder,std::allocator<FC::XMLTestApp::spClientOrder>>>>>,
1>            Modifier=FC::ClientOrder::change_status_by_sp
1>        ]
1>        and
1>        [
1>            Node=boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<FC::XMLTestApp::spClientOrder,std::allocator<FC::XMLTestApp::spClientOrder>>>>
1>        ]
1>        and
1>        [
1>            Node=boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<FC::XMLTestApp::spClientOrder,std::allocator<FC::XMLTestApp::spClientOrder>>>>>
1>        ]
1>        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>Build log was saved at "file://c:\Program Files\Microsoft Visual Studio\MyProjects\XMLTest\XMLTest\Debug\BuildLog.htm"
1>XMLTest - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

// SOLUTION (provided by stefaanv)

I was using modify() as a member function of m_micOrders. I should have been using modify() as a member function of the index object that the iterator applies to, such that the updateOrder() functions should be corrected to look like this...

bool XMLTestApp::updateOrder(const std::string& sClOrdID,char cOrdStatus)
    { 
        OrderMIC::nth_index<1>::type& index = m_micOrders.get<1>(); 
        OrderMIC::nth_index<1>::type::iterator i = index.find( sClOrdID ); 
        OrderMIC::nth_index<1>::type::iterator iEnd = index.end(); 
        if ( i != iEnd ) 
        { 
            // FOUND 
            return index.modify(i,FC::ClientOrder::change_status_by_sp(cOrdStatus)); 
        } 
        return false; 
    } 
Was it helpful?

Solution

(Solution provided by stefaanv copied from the original question. I put this hear so that the question doesn't show up as unanswered anymore. @Steve Hibbert: Feel free to copy it yourself again as another answer and accept it.)

modify() was used as a member function of m_micOrders. Instead, modify() should have been used as a member function of the index object that the iterator applies to, such that the updateOrder() functions should be corrected to look like this...

bool XMLTestApp::updateOrder(const std::string& sClOrdID,char cOrdStatus)
    { 
        OrderMIC::nth_index<1>::type& index = m_micOrders.get<1>(); 
        OrderMIC::nth_index<1>::type::iterator i = index.find( sClOrdID ); 
        OrderMIC::nth_index<1>::type::iterator iEnd = index.end(); 
        if ( i != iEnd ) 
        { 
            // FOUND 
            return index.modify(i,FC::ClientOrder::change_status_by_sp(cOrdStatus)); 
        } 
        return false; 
    } 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top