只是对伟大的JohannesD answer 的一个小补充。
如果没有参数传递给foo 构造函数,数组将被默认初始化。但有时您希望保持底层数组未初始化(可能出于性能原因)。您不能将默认构造函数与可变参数模板一起添加。
解决方法是可变参数模板构造函数的附加参数,以将其与零参数构造函数区分开来:
template<class T, size_t rows, size_t cols>
class array2d
{
std::array<T, rows * cols> m_Data;
public:
array2d() {}
template <typename T, typename... Types>
array2d(T t, Types... ts) : m_Data{ { t, ts... } } {}
};
所以,现在您可以对对象进行大括号初始化,或者让它未初始化:
array2d<int, 6, 8> arr = { 0, 1, 2, 3 }; // contains 0, 1, 2, 3, 0, 0, 0, ...
array2d<int, 6, 8> arr2; // contains garbage
2016 年 7 月 31 日更新
三年过去了,编译器实现者将其产品的标准合规性提高到了默认构造函数在可变参数构造函数的存在下不再被视为模棱两可的水平。因此,在实践中,我们不需要为可变参数构造函数添加额外的T t 参数来消除构造函数的歧义。
两者
array2d() {}
和
array2d() = default;
如果对象是在没有参数的情况下构造的,则数组将保持未初始化状态。这种行为在所有主要编译器上都是一致的。完整示例 (rextester):
#include <array>
#include <iostream>
template<class T, size_t rows, size_t cols>
class array2d
{
public:
std::array<T, rows * cols> m_Data;
array2d() = default;
template <typename... Types>
array2d(Types... ts) : m_Data{ { ts... } } {}
};
int main()
{
array2d<int, 6, 8> arr_init = { 0, 1, 2, 3 };
array2d<int, 6, 8> arr_default;
std::cout << "Initialized: \n";
for(const auto& a : arr_init.m_Data)
std::cout << a << " ";
std::cout << "\n";
std::cout << "Default: \n";
for(const auto& a : arr_default.m_Data)
std::cout << a << " ";
std::cout << "\n";
}
输出:
Initialized:
0 1 2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Default:
2 0 -519559849 32558 1 32558 0 0 -519634912 32558 -526739248 32558 1 0 2 0 6295032 0 -519531243 32558 0 0 -1716075168 32765 6295648 0 4196192 0 6295648 0 -526527271 32558 1 0 2 0 6295032 0 4196845 0 124 0 0 0 4196768 0 4196518 0
删除默认构造函数仍然会导致调用可变参数构造函数并且数组被默认初始化(在我们的例子中是全零)。
感谢@Alek 提出这个话题并引起人们对这些事实的关注,同时也感谢所有致力于编译器开发的人。