简体   繁体   English

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

[英]Passing variadic template arguments to a variadic function

We are using a third-party C library which provides a printf() -style log function, 我们正在使用第三方C库,它提供了printf()样式的日志功能,

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

For reasons that aren't worth going in to, we need to limit the rate at which messages get logged, something along the lines of 由于不值得进入的原因,我们需要限制消息记录的速率,这有点像

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

Fortunately the authors of the C library knew what they were doing, and provided 幸运的是,C库的作者知道他们在做什么,并提供了

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

so writing the above function is a relatively simple matter. 所以写上面的函数是一件相对简单的事情。 Unfortunately however variadic functions don't play well with inlining , and so I came up with a second solution: 不幸的是, 可变功能在内联方面效果不佳 ,所以我想出了第二个解决方案:

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

This works perfectly and inlines the rate limiting condition as we'd like. 这完美地工作,并按照我们的意愿内联速率限制条件。 But I have a couple of questions about it: 但我有几个问题:

  • Is expanding a parameter pack into a C-style variadic function call like this a legal, well-defined thing to do in C++11, or have we just got lucky that it works? 是否将参数包扩展为C风格的可变参数函数调用,这样在C ++ 11中可以做一个合法的,定义明确的事情,或者让我们幸运的是它有效吗?

  • Are the && and std::forward actually necessary here, given we're calling a C function? 鉴于我们正在调用C函数,这里的&&std::forward实际上是否必要? It seems to work just as well if I use const T& , or even just T by value, with or without std::forward . 如果我使用const T& ,或者甚至只是T值,使用或不使用std::forward ,它似乎也能正常工作。

Expanding parameter packs into varargs is valid. 将参数包扩展为varargs是有效的。

And there is no harm in forwarding when you want to forward. 当你想转发时,转发没有坏处。 But taking by const& also communicates something useful. 但是接受const&并传达一些有用的东西。

The values passed to ... will experience "default argument promotions". 传递给...的值将经历“默认参数促销”。 See http://en.cppreference.com/w/cpp/language/variadic_arguments http://en.cppreference.com/w/cpp/language/variadic_arguments

None of these care about references. 这些都不关心参考文献。

You can improve your code. 您可以改进代码。 You can check that the Ts... are valid types to pass to the printing routine, both by "kind of type" and by actually parsing the formatting string and confirming number (and sometimes type) of arguments. 您可以通过“类型”和实际解析格式化字符串并确认参数的数量(有时是类型)来检查Ts...是否是传递给打印例程的有效类型。 If this fails, you can log an error message instead of crashing. 如果失败,您可以记录错误消息而不是崩溃。

I'm not sure that inlining matters for a logging function. 我不确定是否记录了日志记录功能。 Indeed, many C compilers don't inline variadic functions. 实际上,许多C编译器没有内联可变参数函数。 However, you could make it a macro 但是,你可以把它变成一个宏

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

Especially for logging functions, making them a macro is good, because they could use __LINE__ and __FILE__ like this 特别是对于日志记录功能,使它们成为宏是好的,因为它们可以像这样使用__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__)

Notice the string literal catenation of "%s:%d " with the real Fmt which is supposed to always be a literal formal string. 请注意"%s:%d "的字符串文字连接与真正的Fmt ,它应该始终是文字正式字符串。 Typical use would be RATE_LIMITED_LOG("x=%dy=%d", x, y); 典型用途是RATE_LIMITED_LOG("x=%dy=%d", x, y); ... ...

I admit it is low tech and very C like (not using any C++11 gadget), but it works quite well in practice. 我承认它是低技术和非常喜欢(不使用任何C ++ 11小工具),但它在实践中运作良好。 In practice I'm using a software specific prefix to the macro (like my MOM_FATAPRINTF in monimelt.h , which is in C not C++). 在实践中我使用的是软件的具体前缀宏(就像我MOM_FATAPRINTFmonimelt.h ,这在C不是C ++)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM