0

テンプレート パラメーター リストまたはベクトル (および明らかにデータ型) として取得できる小さなテンプレート クラスを作成しています。[ ] 演算子をオーバーロードする必要があります。これを行うには、ベクトルのオーバーロードされた [ ] を使用して、リストの簡単な検索 (次、次、目的のインデックスに到達するまで) を行います。したがって、パラメーターがリストのパラメーターであり、次のような結果に従って実装されているかどうかを typeid で確認しています。

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が機能することを確認したのでわかりません(まあ...)、とにかく、コンパイラは添え字がリストに対しても呼び出されることを認識しているようです。

4

2 に答える 2

5

コンパイラは関数全体をコンパイルする必要があるため、(チェックのために) 実行時に 1 つの分岐が取られなくても、このタイプの実行時チェックを使用してコンパイル エラーを防ぐことはできません。

型に特化できるヘルパー関数を使用してこれを行う方法があります。ただし、複雑になる可能性があり、この場合、標準ライブラリが既に作業を行っているため、自分で行う価値はありません。

std::advance( header にあります) は、イテレータを最大 N 回進めるために使用でき、(または<iterator>によって返されるものなどの) ランダム アクセス イテレータ用に最適化され、定数時間で実行されます。それ以外の場合は、一度に 1 つずつ実行するようにフォールバックします。std::vectorstd::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

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::list または std::vector でコンパイルすると、関数のオーバーロードを使用して、2 つのオーバーロードのどちらを使用するかを決定index_intoします。したがって、正当なもののみをコンパイルし、両方をコンパイルしようとはしません。

これに注意してください。実装では std::vector と std::list のみが許可されます。任意のコンテナを許可したい場合は、を使用するstd::advanceのが一般的で正しい解決策です。

参考までに、 の実装でstd::advaanceも同様の手法を使用しています。実装を見て、それがどのように行われたかを確認できます。

于 2012-07-30T20:49:58.463 に答える
4

std::advanceから使用<iterator>:

const T* operator[](size_t index) const
{
    const_iterator it = m_container.begin();
    std::advance(it, index);
    return &*it;
}
于 2012-07-30T20:49:21.967 に答える