简体   繁体   中英

typeid for container STL

I am writing a little template class which can get as template parameter list or vector (and the data type obviously). I need to overload [ ] operator, to do this I want to use the overloaded [ ] of the vector and make a simple search (next, next, until we get to the desired index) for the list. So I am checking with typeid if parameter is parameter of list and implements according to result like this:

const T* operator[](size_t _index)const
{
    if(typeid(ContainerT<T,std::allocator<T> >) == typeid(vector<T>))
    {
        return m_container[_index];
    }
    else
    {
        const_iterator it = m_container.begin();
        for(int i=0;i<_index;++i)
        {
            ++it;
        }
        return *it;
    }
}

If I dont use the [ ] for the list, everything is ok, but as I use it:

tContainer_t<int, list> list1;
cout<<list1[0]<<endl;

it is not compiling at all and here is the compilation error:

In file included from main.cpp:6:0:
tContainer.h: In member function ‘const T* tContainer_t<T, ContainerT>::operator[](size_t) const [with T = int, ContainerT = std::list, size_t = unsigned int]’:
main.cpp:68:9:   instantiated from here
tContainer.h:80:29: error: no match for ‘operator[]’ in ‘((const tContainer_t<int, std::list>*)this)->tContainer_t<int, std::list>::m_container[_index]’

I dont understand since I checked that the typeid does work (well I think...) and anyway it seems the compiler sees that subscript will also be called for list.

Use std::advance from <iterator> :

const T* operator[](size_t index) const
{
    const_iterator it = m_container.begin();
    std::advance(it, index);
    return &*it;
}

Since the compiler needs to compile the entire function, even though one branch will not be taken at runtime (due to check), then you can't use this type of runtime checking to prevent the compilation error.

There are ways to do this involving using a helper function that can be specialized for the type. However, it can be complicated and in this case, not worth doing yourself, as the standard library has already done the work for you.

std::advance (located in header <iterator> ) can be used to advance an iterator up to N times and is optimized for random-access iterators (like those returned by std::vector or std::deque ) to do it in constant-time. Otherwise it falls back to steping one at a time using ++

// Note, changed signature to return const T&, which is more standard for operator[]
const T& operator[](size_t index) const  
{
   const_iterator itr = m_container.begin();
   std::advance(itr, index);
   return *itr;
}

Edit:

Assuming you wanted to learn how it's done, you would create the following functions, usually in a separate namespace. For now, I'm going to use the original intent of the question, and assume that you're using std::list or std::vector .

namespace helper
{
    template <typename T, typename Alloc>
    typename std::vector<T,Alloc>::const_reference 
    index_into(std::vector<T, Alloc> const& container, std::size_t index)
    {
        return container[index];
    }

    template <typename T, typename Alloc>
    typename std::list<T,Alloc>::const_reference 
    index_into(std::list<T, Alloc> const& container, std::size_t index)
    {
        std::list<T, Alloc>::const_iterator itr = container.begin();
        for(std::size_t i = 0; i < index; ++i) 
        {
            ++itr;
        }
        return *itr;
    }
}
// Change your definition here
const T& operator[](size_t index) const  
{
    return helper::index_into(m_container, index);
}

Why this works: When you compile this with either std::list or std::vector, it uses function overloading to determine which of the two overloads of index_into to use. Hence, it only compiles the one that is legal, and doesn't attempt to compile both.

Note this, implementation only allows std::vector and std::list. If you wanted to allow any container, using std::advance is the generic and correct solution.

FYI, the implementation of std::advaance uses a similar technique. You can look at your implementation to see how it's done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM