C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[1]: イテレータを扱うメンバ関数を派生クラスからカスタマイズ


(過去ログ 95 を表示中)

[トピック内 2 記事 (1 - 2 表示)]  << 0 >>

■56899 / inTopicNo.1)  イテレータを扱うメンバ関数を派生クラスからカスタマイズ
  
□投稿者/ (こ) (1回)-(2011/02/04(Fri) 11:50:03)

分類:[C/C++] 

こんにちは。

2つのイテレータで範囲指定して、走査なんかを行ってくれるテンプレートメンバ関数が
よく使われていますよね。
例えば何かしらのデータベースへの接続を表す FooDB クラスなんかがあるとして:
class FooDB {
public:
    template<typename InputIterator>
    void insert(InputIterator first, InputIterator last);
};
のようにして、データを一度に挿入できるようにしたり。

質問:
この insert() はテンプレートメンバ関数なので、仮想関数にはできないわけですが、
イテレータを扱うメンバ関数を多態的に使ううまいやり方ってないでしょうか?
(基底クラスのポインタや参照から使えて、かつ派生クラス側からある程度処理の内容を
 カスタマイズできるようにしたい)

すぐに思いつくのは以下のようなやり方ですが、1要素に対して処理を行うメンバ関数を
単に繰り返し呼ぶだけでいい場合にしか対処できないんですよね。

class DBInterface {
public:
    virtual void insert(const DBObject &obj) = 0;

    template<typename InputIterator>
    void insert(InputIterator first, InputIterator last) {
        while (first != last) {
            insert(*first);
            ++first;
        }
    }
};

class FooDB : public DBInterface {
public:
    virtual void insert(const DBObject &obj) { /* FooDB 独自の挿入処理 */ }
};

class BarDB : public DBInterface {
public:
    virtual void insert(const DBObject &obj) { /* BarDB 独自の挿入処理 */ }
};

DBInterface *hoge = /* FooDB または BarDB の実体 */;
hoge->insert(std::istreambuf_iterator<DBObject>(std::cin),
             std::istreambuf_iterator<DBObject>());

例えば BarDB に、5要素まとめて高速に挿入する機能があったとしても、
上記の書き方だと1要素ずつ挿入するしかなくなってしまうわけです。

「そんなうまい方法はない」とか、
「このライブラリを使えば〜という条件下である程度なんとかなる」とか、
ご意見を頂けると嬉しいです。

引用返信 編集キー/
■56901 / inTopicNo.2)  Re[1]: イテレータを扱うメンバ関数を派生クラスからカスタマイズ
□投稿者/ (こ) (2回)-(2011/02/04(Fri) 12:20:33)
ああ…すみません。
any_iterator ってのがあるんですね。
http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html

以下のようにすれば何とでもなりそうですね。
もっとまじめに調べればよかった…。失礼いたしました。

class DBInterface {
protected:
    typedef IteratorTypeErasure::any_iterator<DBObject, std::input_iterator_tag> any_iterator;
    virtual void insert_impl(any_iterator first, any_iterator last) = 0;
public:
    template<typename InputIterator>
    void insert(InputIterator first, InputIterator last) {
        insert_impl(any_iterator(first), any_iterator(last));
    }
};

class FooDB : public DBInterface {
protected:
    virtual void insert_impl(any_iterator first, any_iterator last) { /* FooDB 独自の挿入処理 */ }
};

class BarDB : public DBInterface {
protected:
    virtual void insert_impl(any_iterator first, any_iterator last) { /* BarDB 独自の挿入処理 */ }
};

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -