Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 非类型模板参数启用了哪些优化?_C++_Templates_Compiler Optimization_Non Type - Fatal编程技术网

C++ 非类型模板参数启用了哪些优化?

C++ 非类型模板参数启用了哪些优化?,c++,templates,compiler-optimization,non-type,C++,Templates,Compiler Optimization,Non Type,我在上找到了这个示例,它似乎是out StackOverflow中使用的实际示例: template<int N> struct S { int a[N]; }; 或-因为模板在编译时是恒定的,编译器可以使用类似于的语法来考虑if语句死代码的其他分支吗? 尝试2: template<int VERSION = 500> void print (char *s) { if (VERSION == 500) { // print using 50

我在上找到了这个示例,它似乎是out StackOverflow中使用的实际示例:

template<int N>
struct S {
    int a[N];
};

或-因为模板在编译时是恒定的,编译器可以使用类似于

的语法来考虑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;
   }
}
模板
无效打印(字符*s){
如果(版本==500){
//使用500语法打印
}否则如果(版本==600){
//使用600语法打印
}否则{

Std::CUT

非-Cudio>类型名称模板参数有着巨大的潜在应用范围。在他的C++编程语言中,StruouStrup给出了一个有趣的例子,它勾勒出一种处理物理量的类型安全的零开销框架。epts表示基本物理量(如长度或质量)幂的整数,然后定义它们的算术运算。在生成的框架中,可以用速度加速度,也可以用时间除距离,但不能将质量加时间。请查看此想法的行业级实现

对于你的第二个问题,任何合理的编译器都应该能够为你生成完全相同的机器代码

#define FOO

#ifdef FOO
do_foo();
#else
do_bar();
#endif


除了第二个版本更具可读性,而且编译器可以同时捕获两个分支中的错误。使用模板是生成相同代码的第三种方法,但我怀疑它是否会提高可读性。

一个明显的优化是,当使用整数时,编译器有一个常量而不是一个变量:

int foo(size_t); // definition not visible
// vs
template<size_t N>
size_t foo() {return N*N;}
好的。现在循环的迭代次数已经知道了。循环可以相应地展开/优化,这对大小、速度和消除分支都有好处

另外,根据您的示例,
std::array
存在。
std::array
在某些上下文中可能比
std::vector
好得多,因为
std::vector
使用堆分配和非本地内存

还有一种可能性是,某些专门化将有不同的实现。您可以将它们分开,并(潜在地)减少其他引用的定义

当然,
模板
也会对您的程序造成不必要的重复

模板
也需要更长的符号名


返回到您的版本示例:是的,如果编译时已知
版本
,则绝对有可能删除从未执行的代码,并且还可以减少引用的函数。主要区别在于
无效打印(char*s)
的名称比模板短(其符号名称包括所有模板参数)。对于一个函数,这是计算字节数。对于具有许多函数和模板的复杂程序,这一成本可能会迅速上升。

编译器发现消除死代码很容易。这种情况下,如果
s取决于(仅适用于)在
模板上
参数的值或类型。所有分支都必须包含有效代码,但在编译和优化时,死分支会消失

一个典型的例子是使用控制代码流细节的
模板
参数编写的每像素操作。主体可以充满分支,但编译后的输出没有分支

类似的技术也可用于展开循环(比如扫描线循环)。必须注意理解可能产生的代码大小乘法:特别是如果您的编译器缺少ICF(也称为comdat折叠),如gold gcc链接器和msvc(以及其他)所具有的

也可以做一些更有趣的事情,比如手动跳台

您可以执行纯编译时类型检查,而无需任何运行时行为,比如维度分析。或者区分n空间中的点和向量

枚举可用于命名类型或开关。指向函数的指针可启用有效的内联。指向数据的指针可允许“全局”状态可模拟、可思洛或与实现解耦。指向字符串的指针可在代码中使用有效的可读名称。用于各种目的的整数值列表,如索引技巧解包元组。对静态数据的复杂操作,如在多个索引中对数据进行编译时排序,或使用复杂不变量检查静态数据的完整性


我肯定我错过了一些。

一个。你的观点都是正确的,但我要补充的是,你的第一个例子最好是作为
constepr
函数编写的,它将函数的灵活性与静态计算的优化潜力结合起来。喜欢模板符号名称开销这一点。这是一个非常重要的问题考虑嵌入式环境。我喜欢它的内容!你能在这里介绍一些示例代码吗?
#define FOO

#ifdef FOO
do_foo();
#else
do_bar();
#endif
#define FOO_P 1

if (FOO_P)
  do_foo();
else
  do_bar();
int foo(size_t); // definition not visible
// vs
template<size_t N>
size_t foo() {return N*N;}
int foo(double, size_t); // definition not visible
// vs
template<size_t N>
size_t foo(double p) {
 double r(p);
 for (size_t i(0) i < N; ++i) {
  r *= p;
 }
 return r;
}