在构造函数中初始化私有的 std::array 成员

9

我想知道在构造函数中,当初始数组值是构造函数参数时,初始化类的std::array成员的正确方式是什么?

更具体地说,考虑以下示例:

class Car {
  public:
    Car(const std::string& color, int age): color_(color), age_(age) {}
    // ...
  private:
    std::string color_;
    int age_;
};

class ThreeIdenticalCars {
  private:
    std::array<Car, 3> list;
  public:
    ThreeIdenticalCars(const std::string& color, int age):
    // What to put here to initialize list to 3 identical Car(color,age) objects?
   {}
};

显然一种方法是编写list({Car(color,age), Car(color,age), Car(color,age)}),但如果我们想要30辆相同的汽车而不是三辆,这显然无法扩展。

如果我使用std::vector而不是std::array,解决方案将是list(3, Car(color,age)(或list(30, Car(color, age))),但由于在我的问题中列表的大小已知,因此我认为使用std:array更正确。


6
问题在于数组中所包含的对象无法进行默认构建。如果可以进行默认构建,则可以跳过初始化列表,只需在构造函数体中使用循环重新分配每个元素即可。也许这不是最好的方法,但至少是可扩展的。 - Some programmer dude
2
使用std::vectorstd::array都不是更正确或更错误的选择。每种方法都有其优缺点,你需要评估在每种情况下哪种方法更适用。 - Slava
2个回答

6

对于数组版本,一种选择是使用模板函数构建数组。您需要测试是否在发布模式下进行了优化或复制。

   #include <iostream>
#include <array>
#include <tuple>

class Car {
    public:
    Car(const std::string& color, int age): color_(color), age_(age) {}
    // ...
    //private:
    std::string color_;
    int age_;
};

template <typename CarType, typename... Args ,size_t... Is>
std::array<CarType,sizeof...(Is)> make_cars(std::index_sequence<Is...>,Args&&... args )
{
    return { (Is,CarType(args...))... };
}

class ThreeIdenticalCars {
    //private:
    public:
    std::array<Car, 3> list;
  //public:
    ThreeIdenticalCars(const std::string& color, int age) : 
        list(make_cars<decltype(list)::value_type>(
            std::make_index_sequence<std::tuple_size<decltype(list)>::value>(),
            color,
            age
            ))
   {}
};

int main()
{
    ThreeIdenticalCars threecars("red", 10);

    for(auto& car : threecars.list)
        std::cout << car.color_ << " " << car.age_ << std::endl;

    return 0;
}

Demo


1

rmawatson的回答非常好。

这里有一个类似的替代方案,尝试了两个增强功能:

  1. 通过模型进行构建。
  2. 将模型复制N-1次并将最后一个移动到指定位置。

当然,这需要Car是可复制构造的。

#include <array>
#include <string>

class Car {
  public:
    Car(const std::string& color, int age): color_(color), age_(age) {}
    // ...
  private:
    std::string color_;
    int age_;
};

namespace detail
{
    template<std::size_t...Is, class Model>
    auto build_array_impl(std::index_sequence<Is...>, Model&& model)
    {
        constexpr auto size = sizeof...(Is) + 1;
        return std::array<std::decay_t<Model>, size>
        {
            // N-1 copies
            (Is, model)...,

            // followed by perfect forwarding for the last one
            std::forward<Model>(model)
        };
    }
}

template<std::size_t N, class Type>
auto build_array(std::integral_constant<std::size_t, N>, Type&& model)
{
    return detail::build_array_impl(std::make_index_sequence<N-1>(), 
                                    std::forward<Type>(model));
}

class ThreeIdenticalCars {
  private:
    static constexpr auto num_cars = std::size_t(3);
    static constexpr auto num_cars_c = std::integral_constant<std::size_t, num_cars>();
    std::array<Car, num_cars> list;
  public:
    ThreeIdenticalCars(const std::string& color, int age)
    : list(build_array(num_cars_c, Car(color, age)))
   {}
};

int main()
{
    ThreeIdenticalCars tic("red", 1);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接