我有一个包含两个函数foo1和foo2的类,必须按顺序调用:foo1,foo2。
如何强制用户每次调用foo1时调用foo2?
是否可以在编译时检查此序列?
背景是这样的:我正在开发基于流的日志系统,就像cout,cerr等一样:
trace << "This is a log text followed by a number " << 5 << endl;
我需要的是每次调用 trace 时强制用户调用 endl 。必须在另一次调用 trace 之前调用 endl 。
为什么?
这些是我的限制:
答案 0 :(得分:1)
像这样:
#include <iostream>
struct foo_caller {
template<class OtherStuff>
void call_foos(OtherStuff&& other_stuff)
{
foo1();
other_stuff();
foo2();
}
private:
void foo1()
{
std::cout << "foo1" << std::endl;
}
void foo2()
{
std::cout << "foo2" << std::endl;
}
};
int main()
{
foo_caller bar;
bar.call_foos([] {
std::cout << "here is some other stuff" << std::endl;
});
return 0;
}
预期产出:
foo1
here is some other stuff
foo2
答案 1 :(得分:0)
如何强制用户每次调用时调用foo2 foo1?是否可以在编译时检查此序列?
我喜欢你的问题!
经过10分钟左右的思考,我相信答案是否定的。
我曾经宣称软件具有'无限'的灵活性。我错了。
在这里,您已经要求编译器或代码读取另一个贡献者的想法。我认为无法做到。
我认为foo2()可能通过简单地捕获调用时间来确认foo1()之前是在最后一个小时间测量(微秒?毫秒?)内调用的。但这不能保证(中断处理可以延迟10毫秒,以太网可能具有挑战性)而不是你要求的。
期待其他答案!愿他们再次证明我是错的。
(更新)
或许知道错误发生的时间晚于完全不了解。
考虑为每个函数添加一个计数器,在每次调用时递增。
也许foo2()可以断言()foo1()被调用的时间不超过一次?
但如果允许用户在不调用foo1()的情况下调用foo2(),这是否可行?嗯。也许foo2()必须清除两个计数器?
答案 2 :(得分:0)
我不太喜欢这个问题,因为imho应该通过说明背景是什么来改进(即你为什么需要这个?)。然而,我得到了DOUGLAS O. MOENs的回答,并且只是为了OP告诉我这种方法有什么问题我会建议:
class Foo {
private:
bool foo1Called;
public:
Foo() : foo1Called(false) {}
void foo1(){
assert(!foo1Called && "You have to call foo1();foo2();");
/*...*/
foo1Called = true;
}
void foo2(){
assert(foo1Called && "You have to call foo1();foo2();");
/*...*/
foo1Called = false;
}
}
这是可能的,但我仍强烈建议您不要这样做,只需更改界面(如评论中所示:提供一个公开foo
来调用私人foo1
和{{1}按照正确的顺序。实际上,封装的目的只是这个。)
答案 3 :(得分:0)
阅读完修改后,我会建议另一种不需要客户致电endl
的解决方案。
而不是打电话
trace << stuff << endl;
致电
Trace() << stuff;
不同之处在于Trace()
实际上是一个构造函数调用,它返回一个可以转换为std::ostringstream
的对象。此输出缓冲区对象调用endl
和/或在析构函数中打印它或其他任何内容。 (请注意,我们不一定要打印出我们的调试日志。)
你可能不喜欢括号,但这会给你另一个机会:使用正确的构造函数,你也可以写:
Trace("The %s is %d!", "foobar", foobar);
或混合它们:
Trace("The %s is 0x%x", some_string, some_value) << " and then " << some;
这实际上是我们用于记录的内容。