是否为每个不同大小的 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 不需要就好像存在于运行时二进制文件中一样。
大多数方法都很短,应该在使用时内联。所以它们不会被发射到二进制文件中。
如果您开始获取方法的地址并存储它们,您将开始 运行 膨胀,因为您迫使每个不同的方法都存在。
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::array
s 的 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 状态,除非你强迫它存在。
据我了解,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 不需要就好像存在于运行时二进制文件中一样。
大多数方法都很短,应该在使用时内联。所以它们不会被发射到二进制文件中。
如果您开始获取方法的地址并存储它们,您将开始 运行 膨胀,因为您迫使每个不同的方法都存在。
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::array
s 的 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 状态,除非你强迫它存在。