【问题标题】:Can I enforce this operator call count requirement at compile time?我可以在编译时强制执行此运算符调用计数要求吗?
【发布时间】:2013-07-23 10:54:07
【问题描述】:

我有一个类,就接口而言,就像这样简单:

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 */

现在我想知道是否有办法在编译时强制执行此操作,或者使用相同的代理技术,或者使用其他策略。

我想要实现的另一个示例:在将任意数量的 float 传递给操作员之后强制推送至少一个 int

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

【问题讨论】:

  • 请提供预期的用例,就目前而言,肖恩的回答没有理由不起作用。
  • 你愿意为函数调用牺牲运算符语法吗?
  • 一定要支持C++03吗?如果你可以使用 C++11,那么你应该使用可变参数函数模板。

标签: c++ assertions


【解决方案1】:

为什么不使用 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);

它更冗长,但会确保传递偶数个值。

【讨论】:

  • 为什么要重新发明std::pair
  • @Sean 因为这不是我想要解决的问题。我将添加其他示例。
【解决方案2】:

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

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

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

【讨论】:

  • 这正是我目前正在做的事情,我希望有一个我可能忽略的技巧。我接受这个答案是因为在这种特定情况下,“你不能这样做”对我来说比“以另一种方式做”更有用。谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多