6

begin end私は、より一般的なアルゴリズムとデータ構造を自由に記述できるという新しい概念が本当に気に入っています。begin(range)現在、呼び出しとbegin(*range)、型がコレクションへの参照をポインターとして保持している場合とを区別する必要がある場合があります。独自のコレクション型のポインターに対して、begin/end のオーバーロードを常に提供することをお勧めします。

struct Container {
    int values[3];
};

const int* begin(const Container& c);
const int* end(const Container& c);
const int* begin(const Container* c);
const int* end(const Container* c);

template<typename Range>
int Sum(const Range& range)
{
    return std::accumulate(begin(range), end(range), 0);
}

int main(void)
{
    Container c = {1, 2, 3};
    std::cout << Sum(c);
    std::cout << Sum(&c);
}

これが良いアイデアだった場合、これのテンプレートを提供してみませんか:

template<typename Range>
auto begin(const Range* r) -> decltype(begin(*r)){
    using std::begin;
    return begin(*r);
}

template<typename Range>
auto end(const Range* r) -> decltype(end(*r)) { /* ... */ }

int main(void)
{
    Container c = {1, 2, 3};
    std::vector<int> v = {1, 2, 3}
    std::cout << Sum(c);
    std::cout << Sum(&c);
    std::cout << Sum(v);
    std::cout << Sum(&v);
}

これが良いアイデアだった場合、なぜ標準ライブラリはそれを定義しないのでしょうか?

私の質問は:template<typename R> auto begin(const R* r)テンプレートに問題はありますか? これが何らかの理由で失敗するケースはありますか?

4

1 に答える 1

4

これを行うと、配列に対して使用std::begin()およびオーバーロードできなくなります。std::end()

Container c[2] = { };
std::accumulate(begin(c), end(c), 0);

に追加できないため、これはコンパイルされるべきではありませんc[i]が、一般的なオーバーロードではなくオーバーロードが選択され0ているためコンパイルされます。begin(Container*)std::begin(T (&)[N])

別の例:

Container c[2] = { };
auto dist = std::distance(begin(c), end(c));

配列には 2 つの要素があるため、これは に設定する必要がありますが、 3 に等しいためdist=2代わりに取得します。dist=3end(*c) - begin(*c)

于 2012-12-17T17:47:33.677 に答える