容器STL的typeid

时间:2012-07-30 20:38:59

标签: c++ stl containers typeid

我正在编写一个小模板类,它可以作为模板参数列表或向量(显然是数据类型)。 我需要重载[]运算符,为此我想使用向量的重载[]并对列表进行简单搜索(下一步,下一步,直到我们得到所需的索引)。 所以我用typeid检查if参数是list的参数并按照这样的结果实现:

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;
    }
}

如果我不使用[]作为列表,一切正常,但是当我使用它时:

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

根本没有编译,这是编译错误:

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]’

我不明白,因为我检查了typeid确实有用(我认为......),无论如何,似乎编译器看到下标也会被调用列表。

2 个答案:

答案 0 :(得分:4)

使用std::advance中的<iterator>

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

答案 1 :(得分:4)

由于编译器需要编译整个函数,即使在运行时不会采用一个分支(由于检查),也不能使用这种类型的运行时检查来防止编译错误。

有很多方法可以使用可以专门用于该类型的辅助函数。但是,它可能很复杂,在这种情况下,不值得自己做,因为标准库已经为你完成了工作。

std::advance(位于标头<iterator>中)可用于将迭代器推进N次,并针对随机访问迭代器进行优化(如std::vector或{{返回的迭代器) 1}})在恒定时间内完成。否则,它会使用std::deque

一次退回到一个步骤
++

编辑:

假设您想要了解它是如何完成的,您将创建以下函数,通常在单独的命名空间中。目前,我将使用问题的原始意图,并假设您正在使用// 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; } std::list

std::vector

为什么会这样:当你使用std :: list或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); } 的两个重载中的哪一个。因此,它只编译合法的那个,并且不会尝试编译它们。

注意这一点,实现只允许std :: vector和std :: list。如果您想允许任何容器,则使用index_into是通用且正确的解决方案。

仅供参考,std::advance的实施使用了类似的技术。您可以查看您的实现,看看它是如何完成的。