非constexpr变量模板的开销为零吗?

时间:2018-08-18 08:55:06

标签: c++ c++14 variable-templates

我的意思是,当实例化一个非constexpr的模板变量时会产生什么?

考虑一个计算阶乘的基本变量模板:

template<int N>
int fat = N*(fat<N-1>);

template<>
int fat<0> = 1;

int main() {
    return fat<5>;
}

我的直觉是它会生成如下内容:

int fat0 = 1;
int fat1 = 1*fat0;
int fat2 = 2*fat1;
int fat3 = 3*fat2;
int fat4 = 4*fat3;
int fat5 = 5*fat4;

int main() {
    return fat5;
}

我试图在C++ Insights上进行查看,但是生成的代码如下:

template<int N>
const int fat = N*(fat<N-1>);

template<>
const int fat<0> = 1;

int main()
{
  return fat<5>;
}

...根本没有帮助。

我的下一个尝试是使用godbolt.org查看(优化的)生成的程序集,看是否有任何区别:

令我惊讶的是,!模板版本的行数比手写的行数大约。 GCC似乎为每个实例生成一个额外的“保护变量”。铛也这样做。

现在,考虑到零开销原则,这些变量应该做些重要。具体来说,在编写“展开”版本时我错过了一些东西。我想念的这个“东西”是什么?

P.S .:为了进一步伤害我的大脑,MSVC采取了相反的方式,并且为模板化版本生成的程序集实际上比没有模板的版本小3倍。但是,我对生成的程序集并没有多大意义,因此我将其排除在主要问题之外。

1 个答案:

答案 0 :(得分:1)

编译器完全按照您的要求进行操作。变量fat是外部链接,因此任何其他实例都必须可以动态链接到该程序的任何其他程序都可以访问。因此,编译器必须生成代码。

但是,如果您声明static,则优化器可以remove进行额外的实例化:

template<int N>
static int fat = N*(fat<N-1>);

template<>
int fat<0> = 1;

int main() {
    return fat<5>;
}

NB:此代码可以用作为什么不将Clang用于c ++的示例。 clang模板堆栈被破坏,Clang返回0。

自2016年以来报告的C虫:bug 29033