可变参数模板是否会导致潜在的代码膨胀?
可变参数模板将能够将某些类型的函数重写为更干净、类型安全的版本。这是 printf
的情况,如 Wikipedia 上给出的示例:
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, T value, Args... args)
{
while (*s) {
if (*s == '%' && *(++s) != '%') {
std::cout << value;
++s;
printf(s, args...); // call even when *s == 0 to detect extra arguments
return;
}
std::cout << *s++;
}
throw std::logic_error("extra arguments provided to printf");
}
但是...据我了解模板,它们意味着每种类型组合的代码重复。因此上述 printf 的可变参数版本将被复制多次。对于大型函数或类来说,这可能会很糟糕。
对于代码重复,可变参数模板是否与标准模板一样危险? 如果是的话,继承技巧还有用吗?
Variadic templates will enable the rewriting of certain kind of functions into cleaner, type-safe versions. It is the case of printf
, as the example given on Wikipedia:
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, T value, Args... args)
{
while (*s) {
if (*s == '%' && *(++s) != '%') {
std::cout << value;
++s;
printf(s, args...); // call even when *s == 0 to detect extra arguments
return;
}
std::cout << *s++;
}
throw std::logic_error("extra arguments provided to printf");
}
But... As far as I understand templates, they imply code duplication for each type combination. So the variadic version of the above printf
s would be copied many times. This could be terrible for large functions or classes.
Are variadic template as perilous as standard templates for code duplication?
If yes, can the inheritance trick still help?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
简短的回答是:“您只需为您使用的内容付费”原则仍然像以前一样适用。
通过比较两个假设实现的生成代码可以看到更长的答案,例如,
使用现代编译器,如果您想完全避免模板,这几乎可以减少到您所编写的内容。在这个“传统”C++03 模板化代码中,我的 g++ 版本内联了全部内容(在编译器中,不是关键字意义上),并且没有明显的提示表明初始化是通过模板函数中的引用完成的,多次,以不同的方式完成。方式。
与等效的可变参数方法相比:
这也会生成几乎相同的代码 - 一些标签和损坏的名称与您期望的不同,但由
g++ -Wall -Wextra -S(4.7 快照)没有显着差异。编译器基本上是动态编写程序所需的所有重载,然后像以前一样进行优化。
以下非模板代码也产生几乎相同的输出:
这里唯一明显的区别是标签和符号名称。
关键是现代编译器可以做“正确的事情”,而不会在模板代码中遇到太多麻烦。如果您在所有模板机制下表达的内容都很简单,那么输出也会很简单。如果不是,那么输出会更大量,但如果您完全避免使用模板,输出也会更大量。
然而,这变得有趣的地方(在我看来)是这样的:我的所有陈述都符合“使用像样的现代编译器”之类的内容。 如果您正在编写可变参数模板,您几乎可以确定您用来编译的是像样的现代编译器。没有笨重的旧式编译器支持可变参数模板。
The short answer is: the "you only pay for what you use" principle still applies exactly as before.
The longer answer can be seen by comparing the generated code for two hypothetical implementations e.g.
With a modern compiler this pretty much reduces to exactly what you'd have written if you wanted to avoid templates all together. In this "traditional" C++03 templated code my version of g++ inlines (in the compiler, not keyword sense) the whole lot and there's no obvious hint that the initializations are done via reference in a template function, several times, in different ways.
Compared with the equivalent variadic approach:
This also produces almost identical code - some of the labels and mangled names are different as you'd expect, but the diff of the generated asm produced by
g++ -Wall -Wextra -S
(a 4.7 snapshot) has no significant differences. The compiler basically is writing all of the overloads your program requires on the fly and then optimizing as before.The following non template code also produces almost identical output:
Here again the only noticeable differences are the labels and symbol names.
The point is a modern compiler can do "what's right" without much hassle in template code. If what you're expressing is simple underneath all the template mechanics the output will be simple. If it's not then the output will be more substantial, but so would the output be if you'd avoided templates entirely.
Where this gets interesting (in my view) however is this: all of my statements were qualified with something like "with an decent modern compiler". If you're writing variadic templates you can almost be certain that what you're using to compile is a decent modern compiler. No clunky old relic compilers support variadic templates.
这肯定是个问题。可能有帮助的一件事是排除常见部分:
It could certainly be a problem. One thing that could help is to factor out the common parts: