在构造函数中初始化private std :: array成员

时间:2018-06-07 12:52:39

标签: c++ initializer-list stdarray

我想知道当初始数组值是构造函数的参数时,在构造函数中初始化类的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辆相同的汽车而不是3辆,这显然无法扩展。

如果不是std::array我使用了std::vector,那么解决方案应该是list(3, Car(color,age)(或list(30, Car(color, age)),但在我的问题中,列表的大小是已知的,我想使用std:array更为正确。

2 个答案:

答案 0 :(得分: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 :(得分:1)

rmawatson给出了很好的答案。

这是一个类似的替代方案,尝试2个增强功能:

  1. 按型号建造。
  2. 将模型复制N-1次并将最后一个移动到位。
  3. 当然,它要求汽车是可复制的。

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