使用constexpr或struct进行元编程

Metaprogramming with constexpr or struct

本文关键字:编程 struct constexpr 使用      更新时间:2023-10-16

我们刚刚开始学习c++ 11中的模板元编程。作为练习,我们编写了一个程序,输出int值的二进制表示形式。我们想出了两种可能的实现方法。第一个方法使用枚举值的递归,而第二个方法使用constexpr函数。

我们的期望是两个实现的结果是相同大小的可执行文件。但是,第一个实现产生9064字节,而第二个实现产生9096字节。我们不介意字节的微小差异,但不明白是什么导致了差异。

我们在没有优化标志的GCC 4.8.2中编译了这个程序,但是,使用-O2标志得到了相同的结果。

#include <iostream>
using namespace std;
template <int val>
struct Bin
{
    enum { value = 10 * Bin<(val >> 1)>::value + (val & 1) };
};
template <>
struct Bin<0>
{
    enum { value = 0 };
};
constexpr int bin(int val)
{
  return val == 0 ? 0 : (10 * bin(val >> 1) + (val & 1));
}

int main()
{
  // Option 1
  cout << Bin<5>::value  << 'n'
       << Bin<27>::value << 'n';
  // Option 2
  cout << bin(5) << 'n'
       << bin(27) << 'n';
}

constexpr函数可以在编译时求值。他们不需要这样做。

对于你提供的代码,编译器确实没有这样做,bin在运行时被调用;这意味着不能将函数从程序集中抛出。通过显式要求值为constexpr并带有

constexpr auto i = bin(5), j = bin(27);

bin的调用在编译时完成,如下所示。

  cout << bin(5) << 'n'
      << bin(27) << 'n'; 

发出的相关代码是

movl $5, %edi # Parameter
callq   bin(int) # Here's the call to bin
movl    std::cout, %edi
movl    %eax, %esi
callq   std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
[...]
movl    $27, %edi # parameter
callq   bin(int) # call to bin
movq    %rbx, %rdi
movl    %eax, %esi
callq   std::basic_ostream<char, std::char_traits<char> >::operator<<(int)

当省略调用时,两个版本的大小相同。