2

背景:
当社のソフトウェアは複数の API を使用してファイル i/o を実行します: FILE*CStdio(およびいくつかの派生物) HANDLE、...

私はFilePointer用の RAII ラッパーを作成しましたFILE*。これは、既存のすべての C コードのドロップイン置換として役立ちました。

新しいコードでは、通常、CStdio の派生クラスまたはラッパー クラスが使用されていました。

最近、SimpleTextFile以前のバージョンの MBCS に加えて、UTF-16LE I/O を処理する を作成しました。

これらのさまざまなクラスのインターフェイスは似ていますが、同一ではありません。ポリシー テンプレート クラスを使用していくつかのユーティリティ アルゴリズムを記述し、ユーティリティ アルゴリズムをさまざまなファイル タイプに適合させることができると考えました。これはある程度成功していますが、ユーティリティ アルゴリズム内で、ある種のライン リーダー フィルターを混在させる必要があることがよくあります。

そして、ここで問題が発生します-フィルター付きの行リーダーを混在させた場合、これが渡されるアルゴリズムは、ポリシークラスを使用して、基になる型に適応する方法を理解できなくなります(R現在はa Wrapper<R>、および a のポリシーは存在しませんWrapper<R>)。

質問:
既存の型に新しい動作を提供しながら、基礎となる型で機能するさまざまなポリシーを引き続き機能させることができる mixin テンプレート クラスを作成するにはどうすればよいですか?

詳細:
ポリシー テンプレート:
StreamPositionPolicy<T>- T に適合した GetPosition() および SetPosition() を 提供します。 - LineReaderPolicy<T>T から行を読み取るためのインターフェイスの汎用セットを提供します。 - TFileNamePolicy<T>に GetFilename() を提供します。

したがって、T が CStdio の派生物、または FILE* の場合、上記は、元のファイル名を探し、行を読み取り、取得するための共通のインターフェイスを提供するために最善を尽くします。

さらに、I Have:
FilteredStringReader<F,R>はフィルターをリーダーに結合します。以前は、次のようにしていました。

template <typename Filter, typename Reader>
class FilteredStringReader
{
    Filter      m_filter;
    Reader &    m_reader;

public:

// Constructors
    FilteredStringReader(
        Filter      filter,
        Reader &    reader
    ) :
        m_filter(filter),
        m_reader(reader)
    {
    }

    bool ReadString(CString & strLine)
    {
        return ReadFilteredString(m_reader, m_filter, strLine);
    }
};

これは、LineReaderPolicy<> を使用するすべてのアルゴリズムでうまく機能します。これは、既定のポリシーが ReadString() インターフェイスの使用を試みることであり、このインターフェイスが既定の (汎用) ポリシーと一致し、問題がないためです。

ただし、このオブジェクトが、他のポリシーの 1 つを使用する必要があるアルゴリズムの 1 つに渡されるとStreamPositionPolicy<FilteredStringReader<F,R>>、このスキームは破綻します。StreamPositionPolicy<>aには aがなく、FilteredStringReader<>aFilteredStringReader<>はデフォルトに適合しませんStreamPositionPolicy<>(ストリーム インターフェイスや名前インターフェイスなどではなく、ライン リーダー インターフェイスのみを提供します)。

そのため、そのような mixin はおそらく CRTP を使用し、その基になるファイル タイプ/リーダー タイプから派生する必要があると考えていました。次に、それはそれらの1つであり、基礎となるリーダーに特化したポリシークラスはすべて成功します。

しかし、それは生涯/所有権/コピーの問題を引き起こします:

template <typename Filter, typename Reader>
class FilteredStringReader : public Reader
{
    Filter      m_filter;

public:

// Constructors
    FilteredStringReader(
        Filter      filter,
        Reader &    reader
    )
        : Reader(reader)
        , m_filter(filter)
    {
    }

    bool ReadString(CString & strLine)
    {
        return ReadFilteredString(m_reader, m_filter, strLine);
    }
};

驚くべきことに、この種の動作 - このポリシー オブジェクトの構築は可能です... ただし、リーダー インスタンスをコピーします (リーダーの実装によっては、これは壮大なアイデアではない可能性があります。または、より可能性が高いのは、一部のリーダー タイプが単純に勝つ可能性があります)。コピーは許可されません)。

リーダー オブジェクトの 1 つのインスタンス (mixin テンプレート インスタンスによってラップされるインスタンス) だけが必要です。

だから、これは間違った道を進んでいるような気がします。

可変個引数テンプレートを利用でき、場合によっては完全転送を使用して、ミックスイン自体とそのベースをインプレースで構築できます。しかし、それは以前の化身の機能の一部を失います: 表示された元のバージョンはFilteredStringReader<F,R>、リーダーの上にレイヤー化され、使用され、その後破棄される可能性があり、リーダー自体の寿命は続きます (または、別のアルゴリズムの目的のためにより深くラップされました)。 )。

そのため、CRTP を使用するのは適切ではないようです。しかし、それから、他のすべてをそのままにして、1つのインターフェイスだけをインターセプトするタイプRのラッパーを作成する方法という元の問題に戻りますか?

4

1 に答える 1