我正在努力完成以下任务:
现在,我目前有一个使用宏的编译时解决方案,如果未使用正确的标志编译库,则解析为do {} while(0)
。
我想将此功能转移到在运行时启用。这样做的最佳方式是什么?
我想做:Base * obj = (isGlobalDebugEnabled) ? new Debug(...) : new Base(...);
类型的事情。我是不是想要这样的东西?
请注意,标准虚函数并不能真正解决问题,因为每个函数都必须在对象的派生(调试)版本中重复,从而无法实现目的。
此外,最低级别的功能是非常高的音量(配置文件时大约6000亿次调用)所以我想为“基类”编译一个编译的零开销解决方案。当然,Debug对象可能更慢。
这就是我想到模板的原因。 注意:除了VS2010功能(基本lambda等)之外,我没有C ++ 11 / boost访问权限。我可以做点什么吗
template <bool debug = false>
class Object {
std::enable_if<debug> void printTrace(); // Add functions based on debug/not
};
void Object::doSomething(...){
<only do this if debug without runtime check> addToTrace(...);
doTheStuff();
}
我看到this link指出了虚假继承与模板方向,如果有帮助的话。
感谢您的帮助
AK
编辑:我刚刚意识到我可能会采用错误的方式 - 也许将Debug对象作为基类,并在Regular对象中使用no-ops覆盖功能。这似乎是一种更好的方式。但是,由于这些高性能要求,我仍然希望避免vtable跳转,所以我猜我的模板问题仍然存在?可能?
EDIT2:正如KerrickSB所指出的,使用的一个例子可能更清楚:
主要的exe代码:
void ComputeSomething() {
Object * obj = (globalDebugFlag) ? new DebugObject(...) : new Object(...);
obj->insertElement(elem); // Inserts in Object, Inserts and traces actions in DebugObject
...
}
其中Object当前是一个单独的DLL,其中globalDebugFlag
是一个(建议的)全局变量,由一个命令设置,该命令通过一个单独的端口而不是导致调用ComputeSomething()的端口。
我计划使用全局跟踪变量,然后将跟踪推回端口(通过处理此端口的全局对象),以便在前端工具上显示。
答案 0 :(得分:3)
根据定义,运行时决策意味着您在运行时的所有成本(而不是编译时间)做出决策。你不会从那里得到解决。
但是,您可以将检查推送到调用堆栈,直到它们不经常发生以满足您的需求为止。当然,更改调试标志的效果会延迟一点(多少取决于您忽略的检查)。使用模板,您可以复制/专门化代码以进行调试和非调试版本,而无需复制源代码。
template <bool debug>
class Object {
void something() {
// branch on compile-time constant - can be optimized
if (!debug) return;
// ...
}
}
template<bool debug>
useObject(Object<debug> o) {
for(int i = 0; i < 10000; ++i) {
// statically calls specialized implementation
o.something();
}
}
debugEnabled ? useObject(Object<true>()) : useObject(Object<false>());
答案 1 :(得分:1)
这是一个非常基本的想法。我不确定它是否会概括或扩展,但我们可以讨论。
static bool debug_mode = /* ... */; // global
class Container
{
struct ContainerImpl
{
virtual ~ContainerImpl() { }
virtual void insert(int) = 0;
std::unique_ptr<ContainerImpl> clone() const = 0;
};
std::unique_ptr<ContainerImpl> impl;
public:
Container()
: impl(debug_mode ? new DebugImpl : new MainImpl)
{ }
Container(Container const & rhs)
: impl(rhs.impl->clone())
{ }
Container(Container && rhs) noexcept
: impl(std::move(rhs.impl))
{ }
// also implement assignment
/*** Main interface ***/
void insert(int x)
{
impl->insert(x);
}
/*** Implementations ***/
struct MainImpl : ContainerImpl { /* main implementation */ };
struct DebugImpl : MainImpl // just for example
{
virtual void insert(int x)
{
// trace insertion
MainImpl::insert(x);
}
std::unique_ptr<ContainerImpl> clone() const
{
return { new DebugImpl(*this); }
}
};
};
现在你可以使用Container
作为普通的值类型对象,它将在内部使用不同的实现,具体取决于标志。