Nested initializer_list for initializing multidimensional arrays
up vote
5
down vote
favorite
For some reasons I have to implement a multidimensional array class in C++.
The array in question is something like this:
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
class Array final
{
private:
std::vector<size_t> shape_;
std::vector<T> data_;
public:
// Some public methods
}
T
is the type of elements stored in the array, and that the dimensions of the array is not templated since the user should be able to reshape the array, for example:
Array<int> array = Array<int>::zeros(3, 2, 4);
array.reshape(4, 6);
Though implementation of the functions mentioned above went quite smoothly, I stuck at the "beginning" of implementing this class, that is to initialize the array...
My questions are as follows:
Is there any method to have an constructor like this, such that nested initializer lists of different depths create different arrays, like:
Array<int> a = {1, 2}; // Dimension: 1, Shape: 2
Array<int> b = {{1}, {2}}; // Dimension: 2, Shape: 2x1
My approach to implement the constructors made these two arrays the same, which is not what I want. Plus, clang complained about the braced scalars, which seem to be the problem. Currently my naive approach which suffers from the problem above looks like this
...
Array() :data_(0), shape_{0} {}
Array(std::initializer_list<T> list) :data_(list), shape_{list.size()} {}
Array(std::initializer_list<Array> lists)
{
// Implementation
}
...
It's easy for the compiler to deduct the types for the following arrays:
Array c = {1, 2}; // T = int
Array d = {1.0, 2.0}; // T = double
But I failed to write a working deduction guide for multidimensional ones:
Array e = {{1, 2}, {3, 4}}; // Expects T = int
Array f = {{1.0, 2.0}, {3.0, 4.0}}; // Expects T = double
Is there any way to write a type deduction guide for this class?
c++ arrays multidimensional-array initializer-list
add a comment |
up vote
5
down vote
favorite
For some reasons I have to implement a multidimensional array class in C++.
The array in question is something like this:
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
class Array final
{
private:
std::vector<size_t> shape_;
std::vector<T> data_;
public:
// Some public methods
}
T
is the type of elements stored in the array, and that the dimensions of the array is not templated since the user should be able to reshape the array, for example:
Array<int> array = Array<int>::zeros(3, 2, 4);
array.reshape(4, 6);
Though implementation of the functions mentioned above went quite smoothly, I stuck at the "beginning" of implementing this class, that is to initialize the array...
My questions are as follows:
Is there any method to have an constructor like this, such that nested initializer lists of different depths create different arrays, like:
Array<int> a = {1, 2}; // Dimension: 1, Shape: 2
Array<int> b = {{1}, {2}}; // Dimension: 2, Shape: 2x1
My approach to implement the constructors made these two arrays the same, which is not what I want. Plus, clang complained about the braced scalars, which seem to be the problem. Currently my naive approach which suffers from the problem above looks like this
...
Array() :data_(0), shape_{0} {}
Array(std::initializer_list<T> list) :data_(list), shape_{list.size()} {}
Array(std::initializer_list<Array> lists)
{
// Implementation
}
...
It's easy for the compiler to deduct the types for the following arrays:
Array c = {1, 2}; // T = int
Array d = {1.0, 2.0}; // T = double
But I failed to write a working deduction guide for multidimensional ones:
Array e = {{1, 2}, {3, 4}}; // Expects T = int
Array f = {{1.0, 2.0}, {3.0, 4.0}}; // Expects T = double
Is there any way to write a type deduction guide for this class?
c++ arrays multidimensional-array initializer-list
1
Does is there a way to pass nested initializer lists in C++11 to construct a 2D matrix? help?
– user4581301
Nov 20 at 6:12
@user4581301 I've seen that question and I don't think that helps with my current situation. In that question the matrix is always 2D, but it's not the case for my Array, and I can't just write as many nested std::initializer_list as I can... Plus that question doesn't help with my second question either.
– Chlorie
Nov 20 at 6:28
add a comment |
up vote
5
down vote
favorite
up vote
5
down vote
favorite
For some reasons I have to implement a multidimensional array class in C++.
The array in question is something like this:
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
class Array final
{
private:
std::vector<size_t> shape_;
std::vector<T> data_;
public:
// Some public methods
}
T
is the type of elements stored in the array, and that the dimensions of the array is not templated since the user should be able to reshape the array, for example:
Array<int> array = Array<int>::zeros(3, 2, 4);
array.reshape(4, 6);
Though implementation of the functions mentioned above went quite smoothly, I stuck at the "beginning" of implementing this class, that is to initialize the array...
My questions are as follows:
Is there any method to have an constructor like this, such that nested initializer lists of different depths create different arrays, like:
Array<int> a = {1, 2}; // Dimension: 1, Shape: 2
Array<int> b = {{1}, {2}}; // Dimension: 2, Shape: 2x1
My approach to implement the constructors made these two arrays the same, which is not what I want. Plus, clang complained about the braced scalars, which seem to be the problem. Currently my naive approach which suffers from the problem above looks like this
...
Array() :data_(0), shape_{0} {}
Array(std::initializer_list<T> list) :data_(list), shape_{list.size()} {}
Array(std::initializer_list<Array> lists)
{
// Implementation
}
...
It's easy for the compiler to deduct the types for the following arrays:
Array c = {1, 2}; // T = int
Array d = {1.0, 2.0}; // T = double
But I failed to write a working deduction guide for multidimensional ones:
Array e = {{1, 2}, {3, 4}}; // Expects T = int
Array f = {{1.0, 2.0}, {3.0, 4.0}}; // Expects T = double
Is there any way to write a type deduction guide for this class?
c++ arrays multidimensional-array initializer-list
For some reasons I have to implement a multidimensional array class in C++.
The array in question is something like this:
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
class Array final
{
private:
std::vector<size_t> shape_;
std::vector<T> data_;
public:
// Some public methods
}
T
is the type of elements stored in the array, and that the dimensions of the array is not templated since the user should be able to reshape the array, for example:
Array<int> array = Array<int>::zeros(3, 2, 4);
array.reshape(4, 6);
Though implementation of the functions mentioned above went quite smoothly, I stuck at the "beginning" of implementing this class, that is to initialize the array...
My questions are as follows:
Is there any method to have an constructor like this, such that nested initializer lists of different depths create different arrays, like:
Array<int> a = {1, 2}; // Dimension: 1, Shape: 2
Array<int> b = {{1}, {2}}; // Dimension: 2, Shape: 2x1
My approach to implement the constructors made these two arrays the same, which is not what I want. Plus, clang complained about the braced scalars, which seem to be the problem. Currently my naive approach which suffers from the problem above looks like this
...
Array() :data_(0), shape_{0} {}
Array(std::initializer_list<T> list) :data_(list), shape_{list.size()} {}
Array(std::initializer_list<Array> lists)
{
// Implementation
}
...
It's easy for the compiler to deduct the types for the following arrays:
Array c = {1, 2}; // T = int
Array d = {1.0, 2.0}; // T = double
But I failed to write a working deduction guide for multidimensional ones:
Array e = {{1, 2}, {3, 4}}; // Expects T = int
Array f = {{1.0, 2.0}, {3.0, 4.0}}; // Expects T = double
Is there any way to write a type deduction guide for this class?
c++ arrays multidimensional-array initializer-list
c++ arrays multidimensional-array initializer-list
asked Nov 20 at 5:28
Chlorie
334
334
1
Does is there a way to pass nested initializer lists in C++11 to construct a 2D matrix? help?
– user4581301
Nov 20 at 6:12
@user4581301 I've seen that question and I don't think that helps with my current situation. In that question the matrix is always 2D, but it's not the case for my Array, and I can't just write as many nested std::initializer_list as I can... Plus that question doesn't help with my second question either.
– Chlorie
Nov 20 at 6:28
add a comment |
1
Does is there a way to pass nested initializer lists in C++11 to construct a 2D matrix? help?
– user4581301
Nov 20 at 6:12
@user4581301 I've seen that question and I don't think that helps with my current situation. In that question the matrix is always 2D, but it's not the case for my Array, and I can't just write as many nested std::initializer_list as I can... Plus that question doesn't help with my second question either.
– Chlorie
Nov 20 at 6:28
1
1
Does is there a way to pass nested initializer lists in C++11 to construct a 2D matrix? help?
– user4581301
Nov 20 at 6:12
Does is there a way to pass nested initializer lists in C++11 to construct a 2D matrix? help?
– user4581301
Nov 20 at 6:12
@user4581301 I've seen that question and I don't think that helps with my current situation. In that question the matrix is always 2D, but it's not the case for my Array, and I can't just write as many nested std::initializer_list as I can... Plus that question doesn't help with my second question either.
– Chlorie
Nov 20 at 6:28
@user4581301 I've seen that question and I don't think that helps with my current situation. In that question the matrix is always 2D, but it's not the case for my Array, and I can't just write as many nested std::initializer_list as I can... Plus that question doesn't help with my second question either.
– Chlorie
Nov 20 at 6:28
add a comment |
1 Answer
1
active
oldest
votes
up vote
1
down vote
The only possible solution that would only involve initializer_list
would be to declare a number of constructors that equals the number of possible dimensions:
template<class T>
Array(std::initializer_list<T>)
template<class T>
Array(std::initializer_list<std::initializer_list<T>>)
...
The reason is given in [temp.deduc.call]/1: (P the template parameter)
If removing references and cv-qualifiers from P gives std::initializer_list [...] and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument [...]
Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context
So if the function parameter is std::initializer_list<T>
the nested element of the initializer list argument can not be itself an initializer list.
If you don't want to declare that many constructors, the other option is to explictly specify that the argument is of type std::initializer_list
in order to avoid template argument deduction. Below I use a class named "nest" just because its name is shorter:
#include<initializer_list>
using namespace std;
template<class T>
struct nest{
initializer_list<T> value;
nest(initializer_list<T> value):value(value){}
};
template<class T>
nest(initializer_list<T>)->nest<T>;
struct x{
template<class T>
x(initializer_list<T>);
};
int main(){
x a{1,2,3,4};
x b{nest{1,2},nest{3,4}};
x c{nest{nest{1},nest{2}},nest{nest{3},nest{4}}};
}
1
@PiotrSkotnicki I do know! nest is intended to be used as initializer list, that is just used to initialize an object. The constructor of x is not supposed to store the initializer_list.
– Oliv
Nov 20 at 11:31
Thanks for your answer! By the way you said that this is "The only possible solution that would only involve initializer_list", what if the question is not restricted to initializer_list?
– Chlorie
Nov 22 at 8:19
@Chlorie I had thought about a trick involving aggregates initialization and brace elision but I was erroneous. On the other I can't make a logical proof there are no other solutions. Now I seriously doubt there is any.
– Oliv
Nov 22 at 8:46
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
The only possible solution that would only involve initializer_list
would be to declare a number of constructors that equals the number of possible dimensions:
template<class T>
Array(std::initializer_list<T>)
template<class T>
Array(std::initializer_list<std::initializer_list<T>>)
...
The reason is given in [temp.deduc.call]/1: (P the template parameter)
If removing references and cv-qualifiers from P gives std::initializer_list [...] and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument [...]
Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context
So if the function parameter is std::initializer_list<T>
the nested element of the initializer list argument can not be itself an initializer list.
If you don't want to declare that many constructors, the other option is to explictly specify that the argument is of type std::initializer_list
in order to avoid template argument deduction. Below I use a class named "nest" just because its name is shorter:
#include<initializer_list>
using namespace std;
template<class T>
struct nest{
initializer_list<T> value;
nest(initializer_list<T> value):value(value){}
};
template<class T>
nest(initializer_list<T>)->nest<T>;
struct x{
template<class T>
x(initializer_list<T>);
};
int main(){
x a{1,2,3,4};
x b{nest{1,2},nest{3,4}};
x c{nest{nest{1},nest{2}},nest{nest{3},nest{4}}};
}
1
@PiotrSkotnicki I do know! nest is intended to be used as initializer list, that is just used to initialize an object. The constructor of x is not supposed to store the initializer_list.
– Oliv
Nov 20 at 11:31
Thanks for your answer! By the way you said that this is "The only possible solution that would only involve initializer_list", what if the question is not restricted to initializer_list?
– Chlorie
Nov 22 at 8:19
@Chlorie I had thought about a trick involving aggregates initialization and brace elision but I was erroneous. On the other I can't make a logical proof there are no other solutions. Now I seriously doubt there is any.
– Oliv
Nov 22 at 8:46
add a comment |
up vote
1
down vote
The only possible solution that would only involve initializer_list
would be to declare a number of constructors that equals the number of possible dimensions:
template<class T>
Array(std::initializer_list<T>)
template<class T>
Array(std::initializer_list<std::initializer_list<T>>)
...
The reason is given in [temp.deduc.call]/1: (P the template parameter)
If removing references and cv-qualifiers from P gives std::initializer_list [...] and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument [...]
Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context
So if the function parameter is std::initializer_list<T>
the nested element of the initializer list argument can not be itself an initializer list.
If you don't want to declare that many constructors, the other option is to explictly specify that the argument is of type std::initializer_list
in order to avoid template argument deduction. Below I use a class named "nest" just because its name is shorter:
#include<initializer_list>
using namespace std;
template<class T>
struct nest{
initializer_list<T> value;
nest(initializer_list<T> value):value(value){}
};
template<class T>
nest(initializer_list<T>)->nest<T>;
struct x{
template<class T>
x(initializer_list<T>);
};
int main(){
x a{1,2,3,4};
x b{nest{1,2},nest{3,4}};
x c{nest{nest{1},nest{2}},nest{nest{3},nest{4}}};
}
1
@PiotrSkotnicki I do know! nest is intended to be used as initializer list, that is just used to initialize an object. The constructor of x is not supposed to store the initializer_list.
– Oliv
Nov 20 at 11:31
Thanks for your answer! By the way you said that this is "The only possible solution that would only involve initializer_list", what if the question is not restricted to initializer_list?
– Chlorie
Nov 22 at 8:19
@Chlorie I had thought about a trick involving aggregates initialization and brace elision but I was erroneous. On the other I can't make a logical proof there are no other solutions. Now I seriously doubt there is any.
– Oliv
Nov 22 at 8:46
add a comment |
up vote
1
down vote
up vote
1
down vote
The only possible solution that would only involve initializer_list
would be to declare a number of constructors that equals the number of possible dimensions:
template<class T>
Array(std::initializer_list<T>)
template<class T>
Array(std::initializer_list<std::initializer_list<T>>)
...
The reason is given in [temp.deduc.call]/1: (P the template parameter)
If removing references and cv-qualifiers from P gives std::initializer_list [...] and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument [...]
Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context
So if the function parameter is std::initializer_list<T>
the nested element of the initializer list argument can not be itself an initializer list.
If you don't want to declare that many constructors, the other option is to explictly specify that the argument is of type std::initializer_list
in order to avoid template argument deduction. Below I use a class named "nest" just because its name is shorter:
#include<initializer_list>
using namespace std;
template<class T>
struct nest{
initializer_list<T> value;
nest(initializer_list<T> value):value(value){}
};
template<class T>
nest(initializer_list<T>)->nest<T>;
struct x{
template<class T>
x(initializer_list<T>);
};
int main(){
x a{1,2,3,4};
x b{nest{1,2},nest{3,4}};
x c{nest{nest{1},nest{2}},nest{nest{3},nest{4}}};
}
The only possible solution that would only involve initializer_list
would be to declare a number of constructors that equals the number of possible dimensions:
template<class T>
Array(std::initializer_list<T>)
template<class T>
Array(std::initializer_list<std::initializer_list<T>>)
...
The reason is given in [temp.deduc.call]/1: (P the template parameter)
If removing references and cv-qualifiers from P gives std::initializer_list [...] and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument [...]
Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context
So if the function parameter is std::initializer_list<T>
the nested element of the initializer list argument can not be itself an initializer list.
If you don't want to declare that many constructors, the other option is to explictly specify that the argument is of type std::initializer_list
in order to avoid template argument deduction. Below I use a class named "nest" just because its name is shorter:
#include<initializer_list>
using namespace std;
template<class T>
struct nest{
initializer_list<T> value;
nest(initializer_list<T> value):value(value){}
};
template<class T>
nest(initializer_list<T>)->nest<T>;
struct x{
template<class T>
x(initializer_list<T>);
};
int main(){
x a{1,2,3,4};
x b{nest{1,2},nest{3,4}};
x c{nest{nest{1},nest{2}},nest{nest{3},nest{4}}};
}
edited Nov 20 at 11:40
answered Nov 20 at 11:21
Oliv
7,8651853
7,8651853
1
@PiotrSkotnicki I do know! nest is intended to be used as initializer list, that is just used to initialize an object. The constructor of x is not supposed to store the initializer_list.
– Oliv
Nov 20 at 11:31
Thanks for your answer! By the way you said that this is "The only possible solution that would only involve initializer_list", what if the question is not restricted to initializer_list?
– Chlorie
Nov 22 at 8:19
@Chlorie I had thought about a trick involving aggregates initialization and brace elision but I was erroneous. On the other I can't make a logical proof there are no other solutions. Now I seriously doubt there is any.
– Oliv
Nov 22 at 8:46
add a comment |
1
@PiotrSkotnicki I do know! nest is intended to be used as initializer list, that is just used to initialize an object. The constructor of x is not supposed to store the initializer_list.
– Oliv
Nov 20 at 11:31
Thanks for your answer! By the way you said that this is "The only possible solution that would only involve initializer_list", what if the question is not restricted to initializer_list?
– Chlorie
Nov 22 at 8:19
@Chlorie I had thought about a trick involving aggregates initialization and brace elision but I was erroneous. On the other I can't make a logical proof there are no other solutions. Now I seriously doubt there is any.
– Oliv
Nov 22 at 8:46
1
1
@PiotrSkotnicki I do know! nest is intended to be used as initializer list, that is just used to initialize an object. The constructor of x is not supposed to store the initializer_list.
– Oliv
Nov 20 at 11:31
@PiotrSkotnicki I do know! nest is intended to be used as initializer list, that is just used to initialize an object. The constructor of x is not supposed to store the initializer_list.
– Oliv
Nov 20 at 11:31
Thanks for your answer! By the way you said that this is "The only possible solution that would only involve initializer_list", what if the question is not restricted to initializer_list?
– Chlorie
Nov 22 at 8:19
Thanks for your answer! By the way you said that this is "The only possible solution that would only involve initializer_list", what if the question is not restricted to initializer_list?
– Chlorie
Nov 22 at 8:19
@Chlorie I had thought about a trick involving aggregates initialization and brace elision but I was erroneous. On the other I can't make a logical proof there are no other solutions. Now I seriously doubt there is any.
– Oliv
Nov 22 at 8:46
@Chlorie I had thought about a trick involving aggregates initialization and brace elision but I was erroneous. On the other I can't make a logical proof there are no other solutions. Now I seriously doubt there is any.
– Oliv
Nov 22 at 8:46
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53386756%2fnested-initializer-list-for-initializing-multidimensional-arrays%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Does is there a way to pass nested initializer lists in C++11 to construct a 2D matrix? help?
– user4581301
Nov 20 at 6:12
@user4581301 I've seen that question and I don't think that helps with my current situation. In that question the matrix is always 2D, but it's not the case for my Array, and I can't just write as many nested std::initializer_list as I can... Plus that question doesn't help with my second question either.
– Chlorie
Nov 20 at 6:28