Заполнить std:: array в списке инициализации члена
Следующий код работает, но я бы хотел избежать предупреждения:
предупреждение: 'fitness:: vect_' должно быть инициализировано в список инициализации членов [-WeffС++]
когда он скомпилирован с помощью переключателя g++ -Weffc++
:
#include <array>
template<class T, unsigned N>
class fitness
{
public:
explicit fitness(T v)
{
static_assert(N, "fitness zero length");
vect_.fill(v);
}
private:
std::array<T, N> vect_;
};
int main()
{
fitness<double, 4> f(-1000.0);
return 0;
}
Следует ли игнорировать предупреждение? Есть ли способ заполнить vect_
в списке инициализации конструктора (без изменения его типа)?
Ответы
Ответ 1
Функция, которая генерирует символ filled_array
, должна иметь свое возвращаемое значение:
template<unsigned N, typename T>
std::array<T, N> filled_array_sized( T const& t ) {
std::array<T, N> retval;
retval.fill( t );
return retval;
}
но для этого требуется передать хотя бы размер N
, если не тип T
.
template<typename T>
struct array_filler {
T && t;
template<typename U, unsigned N>
operator std::array<U, N>()&& {
return filled_array_sized<N, U>( std::forward<T>(t) );
}
array_filler( T&& in ):t(std::forward<T>(in)) {}
};
template<typename T>
array_filler< T >
filled_array( T&& t ) {
return array_filler<T>( t );
}
обратите внимание, что сохранение возвращаемого значения filled_array
в auto
не рекомендуется.
Использование:
#include <array>
template<class T, unsigned N>
class fitness
{
public:
explicit fitness(T v): vect_( filled_array( std::move(v) ) ) {
//...
}
//...
Я не знаю, будет ли приведенный выше код генерировать предупреждение в реализации filled_array_size
, но если это так, отключите предупреждение локально.
Ответ 2
Я считаю, что вы можете игнорировать это предупреждение.
Он работает, если вы поместите пустую инициализацию для массива в конструкторе:
#include <array>
template<class T, unsigned N>
class fitness
{
public:
explicit fitness(T v):
vect_{}
{
static_assert(N, "fitness zero length");
vect_.fill(v);
}
private:
std::array<T, N> vect_;
};
int main()
{
fitness<double, 4> f(-1000.0);
return 0;
}
Ответ 3
Попробуйте использовать
explicit fitness(T v) : vect_{}
{
//...
}
Ответ 4
Конструктор по умолчанию (read: value initializer) должен работать нормально в этом случае. Поскольку std::array
является агрегированным типом, каждый элемент будет инициализироваться значением, который для числовых типов, таких как double
, означает нулевую инициализацию, а затем вы можете использовать fill
.
explicit fitness(T v) : vect_() // or vect_{}
{
vect_.fill(v);
}
Возможно, вам лучше использовать std::vector
и его конструктор заполнения, если вы не хотите делать по существу двойную инициализацию. Тогда ваш класс станет следующим:
template<class T>
class fitness
{
public:
explicit fitness(T v, unsigned n) : vect_(n, v)
private:
std::vector<T> vect_;
};
int main()
{
fitness<double> f(-1000.0, 4);
return 0;
}
Вы могли бы, конечно, сохранить N
в качестве параметра шаблона, но нет необходимости делать это, так как длина не должна быть известна во время компиляции. (С другой стороны, если вы придерживаетесь std::array
, вы можете настроить конструктор как constexpr
, хотя для этого может потребоваться некоторое использование шаблона или вспомогательная функция constexpr
, которая возвращает список инициализаторов для правильной работы, Я не играл достаточно с концепциями С++ 11, чтобы знать.)
Ответ 5
Здесь другой способ, очиститель IMHO, используя С++ 11 нестатические инициализаторы элементов данных:
#include <array>
template<class T, unsigned N>
class fitness
{
public:
explicit fitness(T v)
{
static_assert(N, "fitness zero length");
vect_.fill(v);
}
private:
std::array<T, N> vect_ { };
};
int main()
{
fitness<double, 4> f(-1000.0);
return 0;
}