I have a simple example where I create an std::array of some number of Foo elements:
struct Foo
{
Foo(int bar=0) : m_bar(bar)
{
// Code depending on the value of bar
}
int m_bar;
};
const unsigned int num = // get array size
std::array<Foo, num> fooArr;
When I use the initialiser list in the constructor m_bar(bar) this sets all the Foo.m_bar to 0 (as this is the default constructor parameter value). If I don't do that then it is full with garbage values.
My question is how do I pass in another value different from the default one to the constructor of every element in the array without knowing the array size before hand?
I tried using a init list when creating the array, like so: std::array<Foo, 5> fooArr{3} but that only sets the first element's m_bar to 3.
You should simply default-construct the std::array then use its fill method to populate it with a fixed value. Many compilers can optimize this effectively, so you won't pay for the "extra" initialization.
To satisfy your use case, the code would look something like this:
fooArr.fill(Foo(3));
Make an integer_sequence with N elements, and build the array with a pack expansion. This is more useful if your default constructor does nontrivial work or doesn't exist.
template<std::size_t N, class T, std::size_t... Ns>
std::array<T, N> make_repeating_array(const T& value, std::index_sequence<Ns...>) {
return {(void(Ns), value)... };
}
template<std::size_t N, class T>
std::array<T, N> make_repeating_array(const T& value) {
return make_repeating_array<N>(value, std::make_index_sequence<N>());
}
Use as
std::array<Foo, num> fooArr = make_repeating_array<num>(Foo(5));
Related
I'm looking for a solution using only native C++ language features (up to C++17) for accomplishing the following:
std::array<Type, unsigned int Elem> array_{Type(), // 1 - Call constructor on Type()
Type(), // 2 - ...
... , // 3 - ...
Type()} // Elems - Call the Elem:th Type() constructor
In addition, what I'd also like is that each constructor call should be able to take an arbitrary number of arguments.
A concrete example would be to automate the writing of the following:
std::array<std::shared_ptr<int>, 4> array_{std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>()}
I.e., provided that I know Type and Elem, I'd like to automate the process of creating the brace-enclosed initializer list and in the process call Type:s constructor.
Any ideas?
Update, the real problem I'd like to solve is the following:
template <typename Type, unsigned int Size>
class Storage {
public:
Storage(std::initializer_list<Type> initializer) : array_{initializer} {}
private:
std::array<Type, Size> array_;
};
void foo(){
Storage<std::shared_ptr<int>, 100> storage(...);
// or perhaps
auto storage = std::make_shared<Storage<std::shared_ptr<int>, 100>>(here be an initializer list containing calls to 100 std::make_shared<int>());
}
Like this:
#include <array>
#include <memory>
#include <utility>
template <std::size_t ...I>
std::array<std::shared_ptr<int>, sizeof...(I)> foo(std::index_sequence<I...>)
{
return {(void(I), std::make_shared<int>())...};
}
std::array<std::shared_ptr<int>, 4> array_ = foo(std::make_index_sequence<4>());
Guaranteed copy elision from C++17 ensures that the array is constructed in place, and no extra moves happen.
The return statement expands to {(void(0), std::make_shared<int>()), (void(1), std::make_shared<int>())...}. void(...) is not strictly necessary, but Clang emits a warning otherwise.
But if it was my code, I'd write a more generic helper instead:
#include <utility>
template <typename R, typename N, typename F, N ...I>
[[nodiscard]] R GenerateForEach(std::integer_sequence<N, I...>, F &&func)
{
return {(void(I), func(std::integral_constant<N, I>{}))...};
}
template <typename R, auto N, typename F>
[[nodiscard]] R Generate(F &&func)
{
return (GenerateForEach<R, decltype(N)>)(std::make_integer_sequence<decltype(N), N>{}, std::forward<F>(func));
}
Then:
auto array_ = Generate<std::array<std::shared_ptr<int>, 4>, 4>([](auto){return std::make_shared<int>();});
While the lambda discards the index in this case, it often ends up being useful, especially given that in [](auto index){...}, index.value is constexpr.
I was writting some class that map specific multidimensionnal array to unidimensionnal array (like 2D array N by M size is like a 1D array NM size you know, and then you can accees the cell [n, m] through [n+mN]). And it was quite boring since I must handle any multidimensional array (forced to copy/paste many times the class definition).
And I found something that could be great in my case: variadic template function.
I would like to have my constructor and accessors using variadic template so my accessors can use any number of parameters (2 for 2D array, 3 for 3D array...) and same for my constructor, since I need to save the size in each dimension (N, M, ...) and multiply then to have the size of my unidimentionnal array.
The problem is that I don't know how to do that :(
Every examples I found relies on two functions, one with one parameter of type T and another one with one parameter of type T and the Args... args).
Is it possible in one function ? Without recursion or so ?
I gave you what I've made so far:
template <typename T, typename... Args>
T returner(T v, Args... args){
return v;
}
template <typename T>
class Array{
public:
int* dim; //contain the size of each dimension
T* array; //the actual array
template<typename... Args>
Array(Args... args){
constexpr int size = sizeof...(Args);
dim = new int[size];
for(int i=0; i<size; i++)
dim[i] = returner(args...);
/*dim[0] should be equal to the first argument, dim[1]
should be equal to the second argument and so on */
}
};
int main(){
Array<int>(2,2,2); // meant to be a 3D array, 2cells in each dimension
return 0:
}
Obviously, "returner" always return the first argument and I understand why, but the only solution I see it to pass the dim array as a parameter and I would like to not do that. Is there a solution ??
PS: I could do that with classical variadic function, like in C, but it would be quite bad in performance :(
This should do what you want (if I understood correctly):
template <typename T>
class Array{
public:
int* dim; //contain the size of each dimension
T* array; //the actual array
template<typename... Args>
Array(Args... args){
constexpr int size = sizeof...(Args);
dim = new int[size]{args...};
}
};
But you'd better use std::vector instead of raw pointers - It would save you a lot of troubles:
template <typename T>
class Array{
public:
std::vector<int> dim; //contain the size of each dimension
std::vector<T> array; //the actual array
template<typename... Args>
Array(Args... args) : dim{args...} {
}
};
I have the following (not compilable) code:
template< size_t N >
void foo( std::array<int, N> )
{
// Code, where "N" is used.
}
int main()
{
foo( { 1,2 } );
}
Here, I want to pass an arbitrary number of ints to a function foo -- for convenience, I will use the std::initializer_list notation.
I tried to use an std::array to aggregate the ints (as shown in the code above), however, the compiler can not deduce the array size since the ints are passed as an std::initializer_list.
Using an std::initializer_list instead of an std::array also does not solve the problem since (in contrast to std::array) the size of the std::initializer_list is not captured as template argument.
Does anyone know which data structure can be used so that the ints can be passed by using the std::initializer_list notation and without passing the template argument N of foo explicitly?
Many thanks in advance
Thanks to core issue 1591, you can use
template <std::size_t N>
void foo( int const (&arr)[N] )
{
// Code, where "N" is used.
}
foo({1, 2, 3});
If using an initializer list is not a must, you can use variadic template parameter packs:
template<size_t S>
void foo_impl(array<int, S> const&)
{
cout << __PRETTY_FUNCTION__ << endl;
}
template<typename... Vals>
auto foo(Vals&&... vals) {
foo_impl<sizeof...(vals)>({ std::forward<Vals>(vals)... });
}
you'd call it as follows:
foo(1,2,3,4,5);
This defers common type checks until the initialization point of std::array (unless you add some admittedly ugly asserts), so you probably should prefer Columbo's answer.
I think the most simple way to ask is due to an example. Assume we have the following type:
class Node
{
// make noncopyable
Node(const Node& ref) = delete;
Node& operator=(const Node& ref) = delete;
// but moveable
Node(Node&& ref) = default;
Node& operator=(Node&& ref) = default;
// we do not have a default construction
Node() = delete;
Node(unsigned i): _i(i) {}
unsigned _i;
};
Now i want to store some of these Nodes in a std::array:
template<unsigned count>
class ParentNode
{
std::array<Node,count> _children;
ParentNode()
// i cannt do this, since i do not know how many nodes i need
// : _children{{Node(1),Node(2),Node(3)}}
: _children() // how do i do this?
{}
};
As stated in the comment, the question is: How do I do this? The unsigned passed to the child should be the index of the array where the child is stored. But more general solutions are also very appreciated!
The following solution I found myself might end up in undefined behavior for more complex types. For a proper well defined solution see accepted answer.
template<unsigned count>
class ParentNode
{
public:
// return by value as this will implicitly invoke the move operator/constructor
std::array<Node,count> generateChildren(std::array<Node,count>& childs)
{
for (unsigned u = 0; u < count; u++)
childs[u] = Node(u); // use move semantics, (correct?)
return std::move(childs); // not needed
return childs; // return by value is same as return std::move(childs)
}
std::array<Node,count> _children;
ParentNode()
// i cannt do this, since i do not know how many nodes i need
// : _children{{Node(1),Node(2),Node(3)}}
: _children(generateChildren(_children)) // works because of move semantics (?)
{}
};
ParentNode<5> f;
The code does compile. But I am not sure if it does what i expect it to do. Maybe someone who has good insight in move semantics and rvalue references can just add some comments:-)
You can use a variadics to generate an array with elements initialized to an arbitrary function of the indices. Using the standard machinery for generating index sequences:
template <int... I> struct indices {};
template <int N, int... I> struct make_indices :
make_indices<N-1,N-1,I...> {};
template <int... I> struct make_indices<0,I...> : indices<I...> {};
it's fairly straightforward:
template <typename T, typename F, int... I>
inline std::array<T, sizeof...(I)> array_maker(F&& f, indices<I...>) {
return std::array<T, sizeof...(I)>{ std::forward<F>(f)(I)... };
}
template <typename T, std::size_t N, typename F>
inline std::array<T, N> array_maker(F&& f) {
return array_maker<T>(std::forward<F>(f), make_indices<N>());
}
Which lets us do anything from duplicating the effect of std::iota:
auto a = array_maker<int,10>([](int i){return i;});
to making an array with the squares of the first 10 natural numbers in reverse order:
const auto a = array_maker<std::string,10>([](int i){
return std::to_string((10 - i) * (10 - i));
});
Since your Node is movable, this allows you to define your ParentNode constructor as:
ParentNode()
: _children(array_maker<Node, count>([](unsigned i){return i+1;}))
{}
See it all put together live at Coliru.
Really, there's not much you can do. You painted yourself into a corner by wanting to put a type with no default constructor into an array of a size determined by a template parameter, and then wanting to initialize the elements with some arbitrary values.
There is nothing you can return from a function which can be put into a braced-init-list and used to initialize an array (or aggregate of any kind) with more than one element. {} doesn't mean "initializer_list". It's a braced-init-list, which can become an initializer_list under certain circumstances, but it can also become the parameters for a constructor call or the elements to use in aggregate initialization.
Your best bet is really to just use a vector and initialize it manually with a loop.
I am implementing an n-dimensional array class which is a template as follows (Note that the data is stored in a linear array whose length is the product of all the dimensions):
template< class valType, int rank >
class NDimensionalArray
{
public:
private:
valType* m_data;
int* m_dimensions;
int m_rank;
};
So the idea is that a user (me) can specify an array of rank 2, and of a certain dimension, ie:
NDimensionalArray<double,2> matrix(10,10);
Now the difficulty is in specializing constructors for 1->n dimensions, each constructor takes n parameters where n is the rank of the array. Now I thought of using a valarray like is used in printf(), however with this defining a 1-dimensional array with 2 dimensions ie:
NDimensionalArray<double,1> matrix(10,10);
would be perfectly acceptable behavior. Is there some neat trick I can use to let the compiler do the repetition? Realistically so long as I know the rank, and have the length of each dimension the constructor can be generic:
{
int nElements = m_dimensions[0];
for ( int i=1 ; i<m_rank ; ++i )
nElements *= m_dimensions[i];
m_data = new valType[nElements];
}
Edit: Note that a similar operation will be needed for accessors.
Also I have considered the option of a constructor which looks like:
NDimensionalArray( const NDimensionalArray<int,1>& dimensions );
Which could be used like:
NDimensionalArray<int,1> dimVec(2); // Need a specification for 1-dimensional arrays.
dimVec(0) = 10;
dimVec(1) = 10;
NDimensionalArray<double,2> matrix(dimVec);
This would be a viable solution, but its ugly compared to the use I would like. Also accessing multi-dimensional arrays would become a serious pain, and seriously slow having to construct a dimension vector for each access.
Okay, I've played with this for a while. Here's some template metaprogramming hackery that does something close to what you want. It lets you specify all dimensions inline, it doesn't do any dynamic memory allocation or other such things. In addition, with a good C++ compiler (I tested with VC++ /O2 option), the code will be fully inlined, with no copies done (in fact, for me it inlined the whole NDimensionalArray constructor at the point of the call). It will typecheck completely at compile-time, and won't let you pass too few or too many dimensions. And it can be reused for indexers. Here goes:
template<class T, int N>
class value_pack : private value_pack<T, N-1>
{
public:
enum { size = N };
value_pack(value_pack<T, N-1> head, const T& tail)
: value_pack<T, N-1>(head)
, value(tail)
{
}
value_pack<T, N+1> operator() (const T& tail) const
{
return value_pack<T, N+1>(*this, tail);
}
template<int I>
const T& get() const
{
return this->value_pack<T, I+1>::value;
}
protected:
const T value;
};
template<class T>
struct value_pack<T, 0>
{
};
struct
{
template <class T>
value_pack<T, 1> operator() (const T& tail) const
{
return value_pack<T, 1>(value_pack<T, 0>(), tail);
}
} const values;
template <class ValType, int Rank>
struct NDimensionalArray
{
NDimensionalArray(value_pack<ValType, Rank> values)
{
// ...
}
};
int main()
{
NDimensionalArray<int, 3> a(values(1)(2)(3));
}
I think the best solution is to take a vector of ints and let the constructor validate it against the template parameter 'rank'.
NDimensionalArray matrix(std::vector<int> matrixDimensions)
{
if (matrixDimensions.size() != rank)
{
throw SomeException();
}
...
}
I don't think any compiler trick can be an alternative here. (Except perhps using macros, if you can think of something, although that wouldn't be a compiler trick strictly speaking.)
Not a direct answer, but check out the blitz library.
There's no good way to do it in C++ as currently standardized. In C++0x, you'll be able to use template parameter packs to approximate (I think I've got the syntax right, but not sure about expansion in requires):
template <class ValType, int Rank>
struct NDimensionalArray
{
template <class... Args>
requires std::SameType<Args, ValType>... && std::True<sizeof...(Args) == Rank>
NDimensionalArray(Args... values)
{
...
}
};
You could take a std::tr1::array. Hmm:
#include <array>
template< class valType, int rank >
class NDimensionalArray
{
public:
NDimensionalArray(const std::tr1::array<rank>& dims);
// ...
};
NDimensionalArray<double,2> foo({10,10});
NDimensionalArray<double,2> bar({10}); // second dimension would be 0
NDimensionalArray<double,1> baz({10,10}); // compile error?
I'm not actually sure if that works! I'll run it through comeau.
Edited As per the comments, looks like this approach would look more like:
std::tr1::array<2> dims = {10, 10};
NDimensionalArray<double,2> foo(dims);
Boost has a multi-array library that uses a custom object for constructing their multidimensional array. It's a really good way to do it; I suggest you study (or better yet, use) their code.