9

constクラスとnon-constクラスのメソッドについてこの質問を検討しています。推奨される回答は、ScottMeyersによるEffectiveC ++から取得されます。ここでは、constメソッドの観点からnon-constメソッドが実装されています。

これをさらに拡張すると、メソッドが参照ではなくイテレータを返す場合、コードの重複をどのように減らすことができますか?リンクされた質問の例を変更する:

class X
{
    std::vector<Z> vecZ;    
public:
    std::vector<Z>::iterator Z(size_t index)
    {
        // ...
    }
    std::vector<Z>::const_iterator Z(size_t index) const
    {
        // ...
    }
};

distance()/ Advance()手法を使用せずに、const_iteratorからイテレータに直接変換することはできないため、constメソッドの観点からnon-constメソッドを実装することはできません。

この例では、コンテナーとしてstd :: vectorを使用しているため、ポインターとして実装されている可能性があるため、実際にはconst_iteratorからイテレーターにキャストできる可能性があります。私はこれに頼りたくありません。より一般的な解決策はありますか?

4

3 に答える 3

5

使用できるトリックがいくつかあります。コンテナへの非constアクセスがある場合は、const_iteratorをイテレータに変えることができます。(あなたがする):

std::vector<Z>::iterator Z(size_t index)
{
    std::vector<Z>::const_iterator i = static_cast<const X&>(*this).Z(index);
    return vecZ.erase(i, i);
}

これを行うこともできます:

std::vector<Z>::iterator Z(size_t index)
{
    return std::next(vecZ.begin(), std::distance(vecZ.cbegin(), static_cast<const X&>(*this).Z(index)));
}

どちらも特にエレガントではありません。なぜ私たちはconst_iterator_cast好きではないのconst_pointer_castですか?多分私達はすべきです。

編集、私は非constメソッドからconstメソッドを使用しようとしていたため、最も明白で洗練されたソリューションを見逃しました。ここで私は反対のことをします:

std::vector<Z>::const_iterator Z(size_t index) const
{
    return const_cast<X&>(*this).Z(index);
}

の結果を間接参照していますが、non-constがのデータを変更しないconst_cast限り、これは未定義の動作ではありません。私が提供した他の2つのソリューションとは異なり、これは私が実際に使用する可能性のあるソリューションです。ZX

于 2013-01-21T19:50:02.983 に答える
2

私はそれがヘルパーでのみ可能であると信じています

typedef int Z;

class X
{
    std::vector<Z> vecZ;    
public:
    std::vector<Z>::iterator foo(size_t index)
    {
        return helper(*this);
    }
    std::vector<Z>::const_iterator foo(size_t index) const
    {
        return helper(*this);
    }

    template <typename T>
    static auto helper(T& t) -> decltype(t.vecZ.begin())
    {
        return t.vecZ.begin();
    }
};

編集 同じことはc++11なしで実装することができます

template <typename T>
struct select
{
    typedef std::vector<Z>::iterator type;
};
template <typename T>
struct select<const T&>
{
    typedef std::vector<Z>::const_iterator type;
};

template <typename T>
static
typename select<T>::type
helper(T t) 
{
    return t.vecZ.begin();
}

しかし、まあ、このアプローチを使用する前に、よく考えるべきだと思います

于 2013-01-21T19:59:28.287 に答える
1

C ++ 11を使用している場合は、テンプレートイテレータクラスで2つのtypedefのみを使用して、constと通常のイテレータを区別するより洗練された(IMHO)方法があります 。http ://www.sjvs.nl/c-実装-const_iterator-and-non-const-iterator-without-code-duplication/

于 2013-07-03T13:56:55.597 に答える