未知(“模板化”)数量的类的初始化列表

时间:2018-06-10 15:01:49

标签: c++ class templates initializer-list

如果我有一个类模板,其中包含一个数组,其中另一个类是具有未定义字段数的类型(数量是模板参数),我该如何运行它们的构造函数(如果它们采用参数)?

这里有一些示例代码:

class ArrayClass
{
public:
    ArrayClass() = delete;
    ArrayClass(int anyParameter) {}
};

template <const int amountOfFields>
class ContainingClass
{
    ArrayClass myArray[amountOfFields];

public:
    ContainingClass();
};

template <const int amountOfFields>
ContainingClass<amountOfFields>::ContainingClass()
    :
    myArray(5)     // doesn't work of cause
{}

是否可以为每个ArrayClass提供相同的参数(或不同的参数),无论它们有多少个? (我基本上不需要它,但它会让事情变得更容易)

2 个答案:

答案 0 :(得分:1)

此案例的C ++标准库中没有任何内容

如果你正在使用GCC进行编译,它有一个名为ranged initialization的专有扩展。使用GCC,您可以编写类似这样的内容(未经测试):

template<size_t amountOfFields>
ContainingClass<amountOfFields>::ContainingClass():
    myArray( { [0 ... (amountOfFields-1)] = 5} )
{ }

如果您正在使用任何其他编译器,则可以使用以下选项。

  1. 正如评论者所说,用std :: vector替换数组,它有你需要的构造函数。但是这会改变RAM布局,即如果你有很多容器,每个容器都有少量元素,那么数组(C数组和C ++ std :: array)会更快,因为少了一个指向追逐的指针。

  2. 从ArrayClass的默认构造函数中删除“= delete”,在ContainingClass构造函数中使用std::fillstd::fill_n来设置初始值。但是,这可能会带来一些小的运行时成本。

  3. 如果你没有太多的元素,从技术上讲,你可以使用一些模板元编程来按照你想要的方式实现静态构造的数组。但是,IMO将会非常难以调试C ++代码(没有编译时调试器)。

  4. 如果代码中有少量不同的模板参数,则可以编写类似

    的函数
    template<size_t N>
    constexpr std::array<ArrayClass,N> fill_array(int val)
    
  5. 将其专门用于您拥有的amountOfFields temple参数的不同值,并在ContainingClass的构造函数中调用该函数。

    其他解决方案也是可能的,例如外部工具,宏,增强等......但我认为2&amp; 4是最合理的解决方法。

答案 1 :(得分:1)

这对我来说对GCC 8.1 / Clang 6.0和C ++ 14有用,虽然我不确定它是否符合标准:

class E {
public:
   E() = delete;
   E(int i) : i_(i) { }
   operator int() const { return i_; }
private: 
   int i_;
};

template <typename T>
T dummy(T val, /* [[maybe_unused]] */ size_t I) { return val; }

template <typename T, size_t... I, typename U>
constexpr auto make_array_impl(U val, std::index_sequence<I...> is) {
   return std::array<T, is.size()>{dummy(val, I)...};
}

template <typename T, size_t N, typename U>
constexpr auto make_array(U val) {
   return make_array_impl<T>(val, std::make_index_sequence<N>{});
}

template <typename T, size_t N>
class A {
public: 
   A(T val) : a_{make_array<T, N>(val)} { }
   void print() { for (auto e : a_) std::cout << e << std::endl; }
private:
   std::array<T, N> a_;
};

int main() {
   A<E, 5> a(-1);    
   a.print();
}

现场演示:https://wandbox.org/permlink/Db9Zpf6gUMvg4MER

更新了更通用的解决方案:

template <typename T, size_t... I, typename... Args>
constexpr auto make_array_impl(std::index_sequence<I...> is, Args&&... args) {
   return std::array<T, is.size()>{ (I, T(std::forward<Args>(args)...))... };
}

template <typename T, size_t N, typename... Args>
constexpr auto make_array(Args&&... args) {
   return make_array_impl<T>(std::make_index_sequence<N>{}, std::forward<Args>(args)...);
}
相关问题