假设我有一个如下定义的调试函数:
namespace debug {
void report(std::string message);
}
我可以提取一些编译器技巧,在编译时,用nop
安全地替换每个调用。我不想调用空函数,我想根本不调用函数。
如果有可能......我可以创建名称空间"也会消失吗?
调试可执行文件将使用定义的符号DEBUGEXECUTABLE
进行编译(我可以想象一些带有宏的技巧)。
答案 0 :(得分:5)
您可以这样做:
namespace debug
{
void report(std::string message); // ToDo - define this somewhere
}
namespace release
{
template <class Y>
void report(Y&&){} // Intentionally do nothing
}
#if defined(DEBUGEXECUTABLE)
namespace foo = debug; // set foo to the debug namespace
#else
namespace foo = release; // set foo to the release namespace
#endif
然后在代码中使用foo::report
。我喜欢这个,因为它最大限度地减少了预处理器宏的使用,并使调试和发布配置中的任何编译器错误大致相似。
在发布模式下传递 r值引用将允许编译器优化任何匿名临时值。对于调试函数系列,您应该通过常量引用传递字符串,以避免采用值复制的任何可能性:void report(const std::string& message);
答案 1 :(得分:3)
这是我能做到的最佳选择。
我们将DEBUG
定义为有report
做某事,然后不做任何事情:(或者我们可以使用您在构建过程中使用的任何符号来区分debug和opt来自生产代码)
#define DEBUG
我们创建两个名称空间。一个称为debug
,另一个称为release
。在每个中我们创建一个匿名命名空间,这使编译器可以轻松检测和丢弃未使用的函数:
namespace debug {
namespace {
void report(std::string const& s) {
std::cerr << s << "\n"; // sample implementation
}
}
}
namespace release {
namespace {
template<class T>
void report(T&&) {} // Or `class...Ts` and `Ts&&...` to handle more than 1 argument optionally.
}
}
这里我们创建一个在发布和调试方面不同的命名空间别名:
#ifdef DEBUG
namespace report=debug;
#else
namespace report=release;
#endif
我们的主要内容:
int main() {
report::report("hello");
}
我们可以在gcc 4.9下看到此结果,其中DEBUG
defined和not位于godbot。正如您所希望看到的那样,当#define DEBUG
未定义时,编译器只生成空main
。
如果已定义,则会编译为您期望的内容。
答案 2 :(得分:0)
namespace debug {
#ifdef DEBUGEXECUTABLE
void report(std::string message);
#else
inline void report(std::string message)
{
//nop - compiler should optimize it
}
#endif
}