Просто небольшое дополнение к великолепному 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
Обновление 31/07/2016
Прошло три года быстро, и разработчики компиляторов улучшили соответствие своих продуктов стандартам до уровня, когда конструктор по умолчанию больше не считается неоднозначным при наличии конструктора с переменными числами. Таким образом, на практике нам не нужен дополнительный аргумент 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 за продвижение этой темы и за внимание к этим фактам, а также благодаря всем людям, усердно работающим над разработкой компилятора.