是否为每个不同大小的 std::array 编译了一个全新的 class?

Is an entirely new class compiled for each differently sized std::array?

据我了解,c++ 模板通过为所需的每种类型编译单独的 class 或函数来工作。对于只会为少数不同类型/参数调用的 classes 或函数来说,这似乎是合乎逻辑的,但对于 std::array 来说,这似乎会导致相同的 class 被编译成数百个不同的版本。

我理解 std::array 相对于 C 风格数组的优势,但如果我的上述假设正确的话,与后者相比,使用前者似乎会产生巨大的二进制大小。

例如,如果说在一个大型程序中我们最终在整个代码中使用了 99 个不同大小的数组,那么我们实际上有:

int arr[1]   = { ... }
int arr[2]   = { ... }
int arr[...] = { ... }
int arr[99]  = { ... }
int arr[100] = { ... }

 std::array<int, 1> arr   = { ... }
 std::array<int, 2> arr   = { ... }
 std::array<int, ...> arr = { ... }
 std::array<int, 99>  arr = { ... }
 std::array<int, 100> arr = { ... }

std::array 示例是否会以整个 class 及其所有函数被编译为二进制文件 99 次结束?

Would the std::array example end up with the entire class and all its functions being compiled into the binary 99 times?

不,对于每个不同的参数,您确实有一个 class 实例化...

但这并不包括所有方法。只会生成实例化方法。

在你的例子中,你只是使用聚合初始化,所以它是相同的。

是的,每个 class 特化都将针对不同的模板参数进行实例化。

class 特化的实例化不会自动实例化其成员函数定义。只有它们的声明被实例化。在使用函数之前,这不会影响二进制代码。

是的,std::array<int,1> 将被编译为与 std::array<int,2> 不同的 class。

不过别担心。由于 std::array 只是 c 数组的薄包装器 (int arr[2]),大多数方法无论如何都会被内联。

所以在某种意义上,std::array<int,1>::operator[]std::array<int,2>::operator[] 将被编译成 两种不同的方法 ,但是这 2 个方法将被编译成 相同的 cpu-指令,并且在打开优化时将内联到调用函数中。

是的,class 模板为每组不同的模板参数生成一个新的 class。

但是 class 不需要就好像存在于运行时二进制文件中一样。

大多数方法都很短,应该在使用时内联。所以它们不会被发射到二进制文件中。

如果您开始获取方法的地址并存储它们,您将开始 运行 膨胀,因为您迫使每个不同的方法都存在。

例如 binary bloat generator:

template<std::size_t...Ns>
std::function<std::type_info const&()> stupid(std::size_t i, std::index_sequence<Ns...>) {
  std::function<std::type_info const&()> retval;
  (
    ((i || (retval = []()->std::type_info const&{
       return typeid( std::array<int, Ns> );
    })) && i--) && ...
  );
  return retval;
}
std::function<std::type_info const&()> stupid( std::size_t i ) {
  return stupid( i, std::make_index_sequence<100>{} );
}

这要求库包含 100 个不同 std::arrays 的 rtti 信息。

但如果您不那种事情,则不需要 rtti。所以它不会注入到您的二进制文件中。

而且我可以用 100 个不同的数组做完全相同的事情

template<std::size_t...Ns>
std::function<std::type_info const&()> stupid(std::size_t i, std::index_sequence<Ns...>) {
  std::function<std::type_info const&()> retval;
  (
    ((i || (retval = []()->std::type_info const&{
       return typeid( int[Ns] );
    })) && i--) && ...
  );
  return retval;
}
std::function<std::type_info const&()> stupid( std::size_t i ) {
  return stupid( i, std::make_index_sequence<100>{} );
}

a "class" 在 C++ 中并不像在其他 OO 语言中那样繁重。没有全局 class 状态,除非你强迫它存在。