Pau*_*aul 5 c++ type-safety variadic-templates c++11
variadic模板printf函数有几种实现方式.一个是这样的:
void printf(const char* s) {
while (*s) {
if (*s == '%' && *++s != '%')
throw std::runtime_error("invalid format string: missing arguments");
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char* s, const T& value, const Args&... args) {
while (*s) {
if (*s == '%' && *++s != '%') {
std::cout << value;
return printf(++s, args...);
}
std::cout << *s++;
}
throw std::runtime_error("extra arguments provided to printf");
}
Run Code Online (Sandbox Code Playgroud)
并且到处都说这个实现是类型安全的,而普通的C(具有可变参数va_arg)则不是.
这是为什么?类型安全是什么意思,这个实现相对于C printf va_arg有什么优势?
对于传递给可变参数模板版本的所有参数,它们的类型在编译时是已知的.这些知识保留在函数中.然后将每个对象传递给cout严重超载的对象operator<<.对于传递的每种类型,此函数都有单独的重载.换句话说,如果你传递了一个int,它正在调用ostream::operator<<(int),如果你传递一个双重的,它就是在调用ostream::operator<<(double).所以,类型仍然保留.并且每个功能都专门用于以适当的方式处理每种类型.这是类型安全.
有了C printf,故事就不同了.该类型不会保留在函数内部.它需要根据格式字符串的内容(可能是运行时值)来计算出来.该函数必须假定传入了正确的格式字符串以匹配参数类型.编译器不强制执行此操作.
还有另一种安全性,那就是参数的数量.如果向C printf函数传递的参数太少,不足以匹配格式字符串,则表明存在未定义的行为.如果你使用可变参数模板做同样的事情,你会得到一个例外,虽然不可取,但它是一个更容易诊断的问题.
安全或类型安全意味着您可以通过查看源代码来判断您的程序行为是否正确。
该语句std::cout << x始终是正确的,假设x具有明确定义的值(并且不是未初始化的);这是你可以通过查看源代码来保证的。
相比之下,C 并不安全:例如,以下代码可能正确也可能不正确,具体取决于运行时输入:
int main(int argc, char * argv[])
{
if (argc == 3)
printf(argv[1], argv[2]);
}
Run Code Online (Sandbox Code Playgroud)
当且仅当第一个参数是包含精确的一个“ %s”的有效格式字符串时,这是正确的。
换句话说,编写正确的 C 程序是可能的,但仅通过检查代码不可能推断其正确性。该printf函数就是这样的一个例子。更一般地说,任何接受变量参数的函数很可能都是不安全的,任何基于运行时值转换指针的函数也是如此。