4

インターフェイスに関しては、次のように単純なクラスがあります。

struct Foo
{
    inline Foo & operator << (int i)
    {
        return *this;
    }
};

次に、次の方法で使用できます。

Foo foo;
foo << 1 << 2 << 3 << 4;

ここで、この演算子の使用を制限したいと思います。たとえば、シーケンス ポイント間で偶数回呼び出されるようにします。

私は現在、内部プロキシ クラスを使用してこの問題に対処しています。制御シーケンスの最後に破棄され、オペレーターが呼び出された回数をチェックするテンポラリが作成されます。

struct Foo
{
    inline Foo() : m_count(0) {}

private:
    struct FooProxy
    {
        friend struct Foo;

        inline ~FooProxy();
        inline struct Foo & operator << (int i);

    private:
        inline FooProxy(struct Foo &foo) : m_foo(foo) {}
        struct Foo &m_foo;
    };

public:
    inline FooProxy operator << (int i);

private:
    int m_count;
};

inline Foo::FooProxy Foo::operator << (int i)
{
    ++m_count;
    return FooProxy(*this);
}

inline Foo & Foo::FooProxy::operator << (int i)
{
    ++m_foo.m_count;
    return m_foo;
}

inline Foo::FooProxy::~FooProxy()
{
    assert(m_foo.m_count % 2 == 0);
}

いくつかの注意点がありますが、ほとんどの場合、次のように機能します。

Foo foo;
foo << 1 << 2 << 3 << 4; /* is OK */
foo << 1 << 2 << 3; /* triggers an assert */

同じプロキシ手法を使用するか、別の戦略を使用して、コンパイル時にこれを強制する方法があるかどうか疑問に思っています。

私が達成したいことの別の例:int任意の数がfloatオペレーターに渡された後、少なくとも 1 つを強制的にプッシュします。

foo << 1 << 2 << 3.f << 4.f << 5; /* is OK */
foo << 1 << 2 << 3.f << 4.f; /* illegal because one `int` is needed */
4

2 に答える 2

1

メンバーではなくテンプレート パラメーターとして状態をエンコードするテンプレート プロキシを使用できます。

ただし、最終的な戻り値を何かに使用しない限り、一部の条件しかチェックできず、他の条件はチェックできません。たとえば、float の前に int が挿入されているか、2 つの float が連続して挿入されていないかを確認できますが、float の後に int が挿入されているかどうかは確認できません。

一般に、無効な状態に対して無効なものに挿入演算子を特殊化するだけで、次の挿入の前に満たす必要がある条件を検出できます。ただし、すべてのプロキシが破壊可能でなければならないため、最終状態を確認することはできません (それぞれが異なるため、中間のプロキシはすべて破壊されます)。

于 2013-07-23T13:55:37.327 に答える