【发布时间】:2018-02-27 00:47:44
【问题描述】:
我想生成一个printf 版本,它会自动将其std::string 参数转换为其c_str() 值。 (我发现printf 语法比 C++ 流更简洁、更简单)。
我想用一些简单的东西。简洁明了是唯一的设计目标。 Boost有类似的东西,但它太复杂了。我根本不关心效率或避免复制。
下面是一个简单的示例,几乎可以使用一个参数。代码有两个问题:
(1) 如何将其扩展到任意数量(或者说至少 3 个)参数?我知道我可以使用可变参数模板,但我不明白如何在这里使用它们。
(2) 当格式参数const char* 与要打印的实际对象之间存在类型不匹配时,如何保持编译器警告(在clang 和-Wall 下)?
编辑:第 (2) 部分几乎已解决。我在myprint() 之前添加了__attribute__((format printf,1,2))。这会进行类型检查,但要求 myprint 是可变的。
示例代码:
#include <stdio.h>
#include <string>
using std::string;
template <typename T>
void myprint(const char* format, T arg){
printf(format, arg);
}
template <>
void myprint(const char* format, string arg){
printf(format,(arg+" STRING ").c_str());
}
int main(){
string x("foo");
myprint ("The value of 1 is: %s\n", "simple"); //works
myprint ("The value of 2 is: %s\n", x); // works
myprint ("The value of 2 is: %d\n", x); // fails - no warning!
printf ("The value of 2 is: %d\n", x.c_str()); // works - warning
return 0;
}
【问题讨论】:
-
如果格式字符串说明符与相应的参数不匹配,
printf()给出未定义的行为(例如,在提供const char *时指定%d)。您对myprint()的第三次调用也是如此 - 当相应的参数是std::string时指定%d,您的代码会将其转换为具有%d格式和const char *的printf()调用。在模板被实例化之前,编译器不能在模板代码中给出类似的警告。 -
无论如何,通过 google,您将能够找到在 C++ 中使用可变参数模板的类型安全
printf()的示例。 -
@Peter - 他的抱怨是,一旦通话结束,警告就不会出现。我怀疑模板代码的某些警告已关闭...? (但我对 Clang 的了解还不够好,这只是一个疯狂的猜测)
-
printf()的编译器警告依赖于编译器扫描格式字符串,并将说明符与参数类型进行比较。编译器不能使用printf()来处理任意格式的字符串(例如,在运行时生成的字符串),并且不会倾向于在不使用编译器特定扩展的情况下对接受const char *的任意函数执行此操作。 -
@kdog:编译时唯一可用的格式字符串在您的
main()函数中。在您实际调用printf()的地方,格式字符串作为变量传递,其值在运行时才知道,因此编译器无法验证printf()调用。但是,您可以让编译器在main()中验证您的mystring()函数调用,您将在其中为格式字符串传递字符串文字。用formatattribute 标记myprintf(),这样编译器就知道你想要这种行为。
标签: c++ templates clang variadic-templates