我在cppreference.com找到了这个例子,这似乎是 StackOverflow 中使用的事实上的示例:
template<int N>
struct S {
int a[N];
};
当然,非类型模板化比这个例子更有值(value)。此语法还支持哪些其他优化?为什么创建它?
我很好奇,因为我的代码依赖于已安装的单独库的版本。我在嵌入式环境中工作,因此优化很重要,但我也希望有可读的代码。话虽这么说,我想使用这种风格的模板来处理版本差异(下面的示例)。首先,我是否正确地思考了这一点?最重要它比使用 #ifdef
语句有好处还是缺点?
尝试1:
template<int VERSION = 500>
void print (char *s);
template<int VERSION>
void print (char *s) {
std::cout << "ERROR! Unsupported version: " << VERSION << "!" << std::endl;
}
template<>
void print<500> (char *s) {
// print using 500 syntax
}
template<>
void print<600> (char *s) {
// print using 600 syntax
}
OR - 由于模板在编译时是不变的,编译器是否可以使用类似于以下的语法来考虑 if 语句死代码的其他分支:
尝试2:
template<int VERSION = 500>
void print (char *s) {
if (VERSION == 500) {
// print using 500 syntax
} else if (VERSION == 600) {
// print using 600 syntax
} else {
std::cout << "ERROR! Unsupported version: " << VERSION << "!" << std::endl;
}
}
这两种尝试都会产生与此相当的输出吗?
void print (char *s) {
#if defined(500)
// print using 500 syntax
#elif defined(600)
// print using 600 syntax
#else
std::cout << "ERROR! Unsupported version: " << VERSION << "!" << std::endl;
#endif
}
如果你看不出我对这一切有点困惑,就我而言,解释越深入越好。
最佳答案
编译器发现消除死代码很容易。在这种情况下,您有一个 if
链(仅)依赖于 template
参数的值或类型。所有分支都必须包含有效的代码,但在编译和优化时,死分支就会消失。
一个典型的例子是使用控制代码流细节的模板
参数编写的每像素操作。主体可以充满分支,但编译后的输出却没有分支。
类似的技术可用于展开循环(例如扫描线循环)。必须小心理解可能导致的代码大小倍增:特别是如果您的编译器缺少 ICF(又名 comdat 折叠),例如 gold gcc 链接器和 msvc(以及其他)所具有的。
还可以完成更奇特的事情,例如手动跳转表。
您可以进行纯粹的编译时类型检查,而无需任何运行时行为,例如维度分析。或者区分 n 空间中的点和 vector 。
枚举可用于命名类型或开关。指向函数的指针以实现高效内联。指向数据的指针,以允许可模拟、可孤立或与实现分离的“全局”状态。指向字符串的指针,以允许代码中高效可读的名称。用于多种目的的整数值列表,例如解包元组的索引技巧。对静态数据的复杂操作,例如对多个索引中的数据进行编译时排序,或者使用复杂的不变量检查静态数据的完整性。
我确信我错过了一些。
关于c++ - 非类型模板参数可以实现哪些优化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27435736/