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传递给操作员之后强制推送至少一个:

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

2

为什么不使用类似 a 的东西FooPair来强制执行均匀性:

struct FooPair
{
  int m_x, m_y;

  FooPair(int x, int) : m_x(x), m_y(y)
  {
  }
};

和:

inline Foo & operator << (const FooPair &pair)
{
  return *this;
}

所以人们不得不称它为:

Foo foo;
foo << FooPair(1,2) << FooPair(3,4);

它更详细,但会确保传递偶数个值。

于 2013-07-23T11:15:42.830 回答
1

您可以使用将状态编码为模板参数而不是成员的模板代理。

但是,除非您将最终返回值用于某事,否则您只能检查某些条件,而不能检查其他条件。例如,您可以检查是否在 float 之前插入了 int,或者是否在一行中插入了两个 float,但您无法检查是否在任何 float 之后插入了 int。

通常,您可以通过简单地将插入运算符专门针对无效状态的某些内容来检测下一次插入之前必须满足的任何条件。但是您无法检查最终状态,因为所有代理都必须是可破坏的(每个代理都不同,因此所有中间代理都将被破坏)。

于 2013-07-23T13:55:37.327 回答