2

背景:
我们的软件使用多个 API 来执行文件 i/o: FILE*CStdio(和几个衍生产品)HANDLE,,...

我为 编写了一个FilePointerRAII 包装器FILE*,它可以很好地替代所有现有的 C 代码。

较新的代码通常使用 CStdio 派生或包装类。

SimpleTextFile最近,除了我们之前版本的 MBCS 之外,我还编写了一个来处理 UTF-16LE i/o。

这些不同类的接口是相似的,但并不完全相同。我想我可以使用策略模板类编写一些实用算法,以使实用算法适应各种文件类型。这有点成功,但是,我经常需要在实用程序算法中混合某种类型的 line-reader-filter。

这就是问题所在 - 如果我混合了带有过滤器的行阅读器,则传递给它的任何算法都不能再使用策略类来确定如何适应底层类型(因为R现在a Wrapper<R>,并且没有针对 a Wrapper<R>) 的策略。

问题:
我如何制作可以为现有类型提供新行为的 mixin 模板类,同时仍然允许对基础类型起作用的各种策略继续工作?

详细信息:
策略模板:
StreamPositionPolicy<T>- 提供适用于 T 的 GetPosition() 和 SetPosition()。 LineReaderPolicy<T>- 提供一组通用接口,用于从 T 中读取一行。 FileNamePolicy<T>- 为 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() 接口,并且此接口与默认(通用)策略匹配,并且生活很好。

但是,如果将此对象传递给需要使用其他策略之一的算法之一 - 例如StreamPositionPolicy<FilteredStringReader<F,R>>,那么这个方案就会失败!a 没有StreamPositionPolicy<>a FilteredStringReader<>, aFilteredStringReader<>不适合默认StreamPositionPolicy<>(它只提供 line reader 接口,不提供流接口或 name 接口等)

所以,我在想这样的 mixin 可能应该使用 CRTP,并从其底层文件类型/阅读器类型派生。然后,它将是其中之一,任何具有基础读者专业化的策略类都会成功。

但这带来了生命周期/所有权/复制问题:

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);
    }
};

令人惊讶的是,这种工作 - 构造这个策略对象是可能的......但它复制了阅读器实例(这可能不是一个伟大的想法,取决于阅读器的实现 - 或者更有可能 - 某些阅读器类型根本就赢了' t 允许复制)。

我只想要我的阅读器对象的一个​​实例——一个由 mixin 模板实例包装的实例,仅此而已。

所以,我觉得这是走错路了。

我可以使用可变参数模板并可能使用完美转发来让我的 mixin 构造本身 + 它的基础就地。但这失去了前一个化身的一些功能:显示的原始版本FilteredStringReader<F,R>可以分层在阅读器之上,使用,然后丢弃,而阅读器本身的生命周期继续(或者为了另一个算法的目的被更深地包装)。

因此,使用 CRTP 似乎不太合适。但是我又回到了最初的问题,即如何为类型 R 制作包装器,它只拦截一个接口,而让所有其他接口不理会?

4

1 回答 1

1

您可以尝试为遵循底层读者策略的过滤器提供策略的部分专业化:

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

假设策略方法让读者参考,那么您只需要提供转换运算符:

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

public:
    operator Reader &() { return m_reader; }
    operator const Reader &() const { return m_reader; }
    // ...
};
于 2014-03-21T14:57:42.140 回答