【问题标题】:Is an entirely new class compiled for each differently sized std::array?是否为每个不同大小的 std::array 编译了一个全新的类?
【发布时间】:2019-08-27 14:43:19
【问题描述】:

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

我了解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 示例最终会导致整个类及其所有函数被编译成二进制 99 次吗?

【问题讨论】:

  • “会导致巨大的二进制文件大小”——试试吧。
  • 相信你的编译器优化器 ;-)

标签: c++ templates instantiation template-specialization


【解决方案1】:

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

但该类不一定存在于运行时二进制文件中。

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

如果你开始获取方法的地址并存储它们,你会开始遇到膨胀,因为你会强制每个不同的方法存在。

例如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>{} );
}

C++ 中的“类”不像其他 OO 语言那样繁重。除非你强制它存在,否则没有全局类状态。

【讨论】:

    【解决方案2】:

    std::array 示例最终会导致整个类及其所有函数被编译成二进制 99 次吗?

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

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

    在你的情况下,你只是使用聚合初始化,所以它是相同的。

    【讨论】:

      【解决方案3】:

      是的,std::array&lt;int,1&gt; 将被编译为与 std::array&lt;int,2&gt; 不同的类。

      但别担心。因为std::array 只是c-arrays (int arr[2]) 的一个薄包装,大多数方法无论如何都会被内联。

      所以从某种意义上说,std::array&lt;int,1&gt;::operator[]std::array&lt;int,2&gt;::operator[] 会被编译成两个不同的方法,但这两个方法会被编译成相同的 cpu 指令 , 并在开启优化时内联到调用者函数中。

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-22
          • 2021-04-23
          • 1970-01-01
          • 1970-01-01
          • 2022-06-10
          相关资源
          最近更新 更多