I have a std:array
something like this:
class MyClass {
private:
std::array<MyComplexType, 10> myArray;
}
In the constructor, I need to do the following:
MyClass::MyClass() : myArray({
MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)),
... repeated 8 more times...
MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4))
})
Now, I want the 10
to be a compile-time constant that I can modify without having to copy&paste more (or less) of those initializers. They are all the same, I just need a "repeat n times". Everything up to and including C 17 is fair game.
I am 99.9% certain this should be doable with some template magic, but so far I came up with nothing that worked. Any ideas?
(And if it is impossible with templates, maybe with macros? Though I would hate having to go that direction...)
CodePudding user response:
If you want to use a std::array
you are going to need to build a helper function, namely a delegating constructor. Your default constructor will then call the delegate to actually initialize the member. That can look like
class MyClass {
public:
// default c'tor, create sequence of 10 integers
MyClass() : MyClass(std::make_index_sequence<10>{})
private:
// delegate, take a sequence and expand the initializer of myArray sizeof...(Is) times
template <std::size_t... Is>
MyClass(std::index_sequence<Is...>) :
myArray{ (Is, MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)))... } {}
std::array<MyComplexType, 10> myArray;
}
You can instead change myArray
to be a vector
instead and that would let you simplify the code to
class MyClass {
public:
MyClass() :
myData(MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)), 10) {}
private:
std::vector<MyComplexType> myData;
}
CodePudding user response:
You could wrap the type into another struct/class which would provide an appropriate default constructor:
int f(int n)
{
return n;
}
struct S
{
S(int n) : n(n) { }
int n;
};
class MyClass
{
struct Wrapper
{
S s;
Wrapper() : s(f(7)) {}
};
std::array<Wrapper, 10> myArray;
};
You're now delegating the initialisation to the wrapper.
You might yet invest some work makeing the need of explicit indirection (myArray[i].s
) obsolete, e.g. wrapping the array itself into another struct/class, too, providing the same interface as a std::array
(as far as you need at least…) but with its iterators and index operators dereferencing to the complex type instead of to the wrapper (i.e. your iterator wraps around an array's iterator with S& operator*() { return i->s; } S* operator->() { return &i->s; }
and further operators like increment just delegating to the wrapped iterator).