Заполните std::array в списке инициализации члена

Следующий код работает, но я хотел бы избежать предупреждения:

предупреждение: 'fitness::vect_' должен быть инициализирован в списке инициализации члена [-WeffC++]

когда он скомпилирован с 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_ в списке инициализации конструктора (без изменения его типа)?

5 ответов

Решение

Функция, которая генерирует 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, но если это так, отключите предупреждение локально.

Я считаю, что вы можете игнорировать это предупреждение.

Это работает, если вы поместите пустую инициализацию для массива в конструкторе:

#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;
}

Попробуй использовать

explicit fitness(T v) : vect_{}
{
//...
}

Конструктор по умолчанию (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 функция, которая возвращает список инициализаторов для правильной работы, я не достаточно разобрался с концепциями C++11, чтобы знать.)

Вот еще один способ, более чистый IMHO, с использованием инициализаторов нестатических элементов данных C++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;
}
Другие вопросы по тегам