将可变参数模板参数传递给可变参数函数

时间:2014-08-26 18:21:13

标签: c++ c++11 variadic-templates variadic-functions perfect-forwarding

我们正在使用提供printf()样式日志功能的第三方C库

void log(const char *format, ...);

由于不值得进入的原因,我们需要限制消息记录的速率,这与

相似。
void rate_limited_log(const char* format, ...)
{
    if (<not too fast>) {
         log(format, ...);
    }
}

幸运的是,C库的作者知道他们在做什么,并提供了

void logv(const char* format, va_list ap);

所以写上面的函数是一件相对简单的事情。不过不幸的是variadic functions don't play well with inlining,所以我想出了第二个解决方案:

template <typename... T>
void rate_limited_log(const char* format, T&&... args)
{
    if (<not too fast>) {
        log(format, std::forward<T>(args)...);
    }
}

这完美地运作并且按照我们的意愿内联速率限制条件。但我有几个问题:

  • 将参数包扩展为C风格的可变参数函数调用,就像在C ++ 11中一样合法,定义明确的事情,或者让我们幸运的是它有效吗?

  • 鉴于我们正在调用C函数,这里实际需要&&std::forward吗?如果我使用const T&,或者只使用T按值,使用或不使用std::forward,它似乎也可以正常工作。

2 个答案:

答案 0 :(得分:8)

将参数包扩展为varargs是有效的。

当你想转发时,转发没有坏处。但是const&采取的措施也传达了一些有用的东西。

传递给...的值将经历&#34;默认参数促销&#34;。见http://en.cppreference.com/w/cpp/language/variadic_arguments

这些都不关心参考文献。

您可以改进代码。您可以检查Ts...是否是有效类型以传递给打印例程,两者都是&#34;类型&#34;通过实际解析格式化字符串并确认参数的数量(有时是类型)。如果失败,您可以记录错误消息而不是崩溃。

答案 1 :(得分:3)

我不确定是否记录了日志记录功能。实际上,许多C编译器没有内联变量函数。但是,你可以把它变成一个宏

#define RATE_LIMITED_LOG(Fmt,...) do { \
   if (not_too_fast())      \
     log(Fmt,__VA_ARGS__);  \
} while(0)

特别是对于日志记录功能,将它们设为宏是好的,因为它们可以像这样使用__LINE____FILE__

#define RATE_LIMITED_LOG_AT2(Fil,Lin,Fmt,...) do {
   if (not_too_fast())
     log("%s:%d " Fmt, Fil, (Lin), __VA_ARGS__);
} while(0)
#define RATE_LIMITED_LOG_AT(Fil,Lin,Fmt,...) \
   RATE_LIMITED_LOG_AT2(Fil,Lin,Fmt,__VA_ARGS__)
#define RATE_LIMITED_LOG(Fmt,...) \
   RATE_LIMITED_LOG_AT(__FILE__,__LINE__,Fmt,__VA_ARGS__)

注意"%s:%d "与真实Fmt的字符串文字连接,它应该始终是一个文字正式字符串。典型用途是RATE_LIMITED_LOG("x=%d y=%d", x, y); ...

我承认它是低技术和非常喜欢(不使用任何C ++ 11小工具),但它在实践中运作良好。在实践中,我使用宏的软件特定前缀(例如monimelt.h中的MOM_FATAPRINTF,这是C而不是C ++)。