3

私は gcc から Visual Studio 2013 に大量のbegin()コードend()を移植しています。

エラー C2440: '': 'unsigned char *' から 'std::_Vector_const_iterator>>' に変換できません

class foo {
    unsigned char* value;
    int length;

    std::vector<unsigned char>::const_iterator begin();
    std::vector<unsigned char>::const_iterator end();
};

std::vector<unsigned char>::const_iterator foo::begin() {
    return std::vector<unsigned char>::const_iterator(value);
}

std::vector<unsigned char>::const_iterator foo::end() {
    return std::vector<unsigned char>::const_iterator(value + length);
}

全体を書き直したくないので、これらの const_iterators を作成する移植可能な方法はありますか?

4

2 に答える 2

5

(const_)iterator基になる値の型へのポインターから構築可能であるという要件がないため、試みていることを実行するための移植可能な方法はありません。libstdc++ はたまたまそのようなコンストラクタを提供しますが、VS 標準ライブラリの実装は提供しません。代わりに、その(const_)iteratorコンストラクターは、基になる値の型へのポインターと、コンテナー自体へのポインターを受け取ります。これは、デバッグ ビルド中に追加の検証を実行するために使用されます。

最も簡単な解決策は、に置き換えることstd::vector<unsigned char>::const_iteratorですunsigned char const *。生のポインタは、s と同じ RandomAccessIterator カテゴリに分類されますvector::(const_)iterator

unsigned char const *foo::begin() {
    return value;
}

unsigned char const *foo::end() {
    return value + length;
}

イテレータをクラス型にする必要がある場合は、カスタム イテレータを作成する必要があります。これはゼロから行うこともできますが、Boost.IteratorFacadeを使用する方がはるかに簡単です。これは、カスタム イテレータの構築に必要な一連のボイラープレートを提供します。

#include <boost/iterator/iterator_facade.hpp>

struct const_foo_iterator : boost::iterator_facade<const_foo_iterator,
                                                    unsigned char const,
                                                    boost::random_access_traversal_tag>
{
  const_foo_iterator() = default;
  const_foo_iterator(unsigned char const *iter) : iter(iter) {}
private:
    friend class boost::iterator_core_access;

    void increment() { ++iter; }
    void decrement() { --iter; }
    void advance(std::ptrdiff_t n) { iter += n; }

    std::ptrdiff_t distance_to(const_foo_iterator const& other) const
    { return iter - other.iter; }

    bool equal(const_foo_iterator const& other) const
    { return this->iter == other.iter; }

    unsigned char const& dereference() const { return *iter; }
    unsigned char const* iter = nullptr;
};

const_foo_iterator foo::begin() {
    return value;
}

const_foo_iterator foo::end() {
    return value + length;
}

static_assert(std::is_same<std::iterator_traits<const_foo_iterator>::value_type,
                           unsigned char>::value, "value_type");
static_assert(std::is_same<std::iterator_traits<const_foo_iterator>::pointer,
                           unsigned char const *>::value, "pointer");
static_assert(std::is_same<std::iterator_traits<const_foo_iterator>::iterator_category,
                           std::random_access_iterator_tag>::value, "iterator_category");

ライブデモ

于 2014-07-10T16:57:52.023 に答える
2

begin()およびend()関数の使用方法によって異なります。これらの関数の呼び出し元が実際にstd::vector<unsigned char>::const_iterator(正確な型を気にしないほど一般的ではなく) を期待している場合は、別の解決策を探す必要があります。

クラスのインターフェイスを変更するのではなく、その実装に回避策を実装することを試みることができます。valueポインタは何のために必要ですか?他に誰がアクセスできますか? プライベート メンバーの場合は、実際の に置き換えて、std::vector<unsigned char>そのdata()メンバー関数 (C++11) または&value[0](C++11 より前) を使用して、ポインターが期待される場所にポインターを渡します。

于 2014-07-10T17:35:28.930 に答える