Initializer list for an unknown (“templated”) amount of classes

时光毁灭记忆、已成空白 提交于 2019-12-24 08:33:51

问题


If I have a class template which contains an array with another class as type with undefined amount of fields (the amount is a template parameter), how do I run their constructors (if they take parameters)?

Here some example code:

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
{}

Is it possible to give every ArrayClass, no matter how many there are, the same parameter (or different ones)? (I don't essentially need it but it would make things easier for me)


回答1:


There’s nothing in the C++ standard libraries for this case

If you’re compiling with GCC, it has a proprietary extension called ranged initialization. With GCC, you can write something like this (untested):

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

If you’re using any other compiler, you have following options.

  1. As said by the commenters, replace array with std::vector, it has the constructor you need. However this will change RAM layout, i.e. if you have lots of containers with small number of elements each, arrays (both C arrays, and C++ std::array) will be faster because one less pointer to chase.

  2. Remove “=delete” from the default constructor of your ArrayClass, use std::fill or std::fill_n in the ContainingClass constructor to set initial values after they’re already constructed. However this might bring some small runtime cost.

  3. If you don’t have too many elements, technically you can use some template metaprogramming to implement statically-constructed arrays the way you want. However, IMO that’ll be substantial amount of very hard to debug C++ code (there’s no compile-time debugger).

  4. If you have small number of different template arguments in your code, you can write a function like

    template<size_t N>
    constexpr std::array<ArrayClass,N> fill_array(int val)
    

specialize it for different values of amountOfFields temple arguments you have, and call the function in the constructor of ContainingClass.

Other solutions are possible, like external tools, macros, boost, etc… But I think 2 & 4 are the most reasonable workarounds.




回答2:


This work for me with GCC 8.1 / Clang 6.0 and C++14, though I am definitely not sure whether it is Standard compliant:

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

Live demo: https://wandbox.org/permlink/Db9Zpf6gUMvg4MER


Updated more generic solution:

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


来源:https://stackoverflow.com/questions/50785002/initializer-list-for-an-unknown-templated-amount-of-classes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!