[array] how to construct boost::array as class member

I would like to use boost::array as a class data member. This raises a problem when constructing it in the initialization list of the class members: class A { boost::array<int, 3> a; A() : a(???) {} // what do I write here ??? }; Is there a way to construct the data member efficiently? By efficiently, I mean using copy constructors instead of default constructors followed by assignments of array elements. I have not found anything in the documentation on this question, and the only initialization method mentioned there is the ={...} syntax, which does not work in this case. Did I miss anything ? The way I managed to do what I wanted was to introduce an auxiliary function: template < typename T > inline boost::array<T, 3> make_array(const T& b1, const T& b2, const T& b3) { boost::array<T, 3> a = { b1, b2, b3 }; return a; } and using it: class A { boost::array<int, 3> a; A() : a(make_array(1,2,3)) {} }; With a compiler doing the return value optimization, this does what I need. Do people think it is an important enough use case, that this would warrant to be added to Boost.Array ? What about TR1's array ? Of course, it would require N overloads of the make_array() functions (unless variadic templates are used :). But at least providing it for e.g. N<10 in boost would be useful, IMHO. -- Sylvain

Sylvain Pion wrote:
I would like to use boost::array as a class data member.
This raises a problem when constructing it in the initialization list of the class members:
class A { boost::array<int, 3> a; A() : a(???) {} // what do I write here ??? };
Is there a way to construct the data member efficiently? By efficiently, I mean using copy constructors instead of default constructors followed by assignments of array elements.
This is not possible with the language today. Hopefully, there will be changes in the next version of the language that make this sort of initialization possible. There are certainly several proposals before the committee. The key problem is that you cannot supply user-declared constructors for aggregate classes, and we rely on array being an aggregate for brace initialization. Likewise, you can't use brace initialization in a constructor initializer list. I should probaby add a small FAQ to the array docs to describe these issues. -- AlisdairM

"AlisdairM" <alisdair.meredith@uk.renaultf1.com> wrote in message news:ebb4tr$6eq$1@sea.gmane.org...
Sylvain Pion wrote:
I would like to use boost::array as a class data member.
This raises a problem when constructing it in the initialization list of the class members:
class A { boost::array<int, 3> a; A() : a(???) {} // what do I write here ??? };
Is there a way to construct the data member efficiently? By efficiently, I mean using copy constructors instead of default constructors followed by assignments of array elements.
This is not possible with the language today. Hopefully, there will be changes in the next version of the language that make this sort of initialization possible. There are certainly several proposals before the committee.
The key problem is that you cannot supply user-declared constructors for aggregate classes, and we rely on array being an aggregate for brace initialization. Likewise, you can't use brace initialization in a constructor initializer list.
I should probaby add a small FAQ to the array docs to describe these issues.
Would not the boost.assign library work here?
class A { boost::array<int, 3> a; A() : a(boost::assign::list_of(1)(2)(3)(4)) {} };
I don't think I've tried it this way yet. Jeff Flinn

Jeff Flinn wrote:
Would not the boost.assign library work here?
class A { boost::array<int, 3> a; A() : a(boost::assign::list_of(1)(2)(3)(4)) {} };
I don't think I've tried it this way yet.
It works, but it's not efficient. It is even incredibly worse that doing the assignments by hand (boost 1.33.1 is better than 1.32 though). See my attached test program. Here is what I get (with g++ 4.1): #default ctor | #copy ctor | #operator= | #dtor make_array 1 | 3 | 0 | 4 hand assignments 4 | 0 | 3 | 4 assign::list_of 1.32 4 | 11 | 3 | 15 assign::list_of 1.33.1 4 | 7 | 3 | 11 -- Sylvain #include <boost/array.hpp> #include <boost/assign.hpp> #include <boost/version.hpp> #include <iostream> struct B { B() { std::cout << "default ctor" << std::endl; } B(const B&) { std::cout << "copy ctor" << std::endl; } B& operator=(const B&) { std::cout << "assign operator" << std::endl; return *this; } ~B() { std::cout << "destructor" << std::endl; } }; template < typename T > inline boost::array<T, 3> make_array(const T& b1, const T& b2, const T& b3) { boost::array<T, 3> a = { { b1, b2, b3 } }; return a; } typedef boost::array<B, 3> Array; struct A { Array array; A(const B &b1, const B &b2, const B &b3) : array(make_array(b1, b2, b3)) {} //{ array[0] = b1; array[1] = b2; array[2] = b3; } //: array(boost::assign::list_of(b1)(b2)(b3)) {} //: array(b1, b2, b3) {} // not [yet] C++ }; int main() { std::cout << "Using Boost version " << BOOST_LIB_VERSION << std::endl; B b; A a(b, b, b); }

Sylvain Pion <Sylvain.Pion <at> sophia.inria.fr> writes:
Jeff Flinn wrote:
Would not the boost.assign library work here?
class A { boost::array<int, 3> a; A() : a(boost::assign::list_of(1)(2)(3)(4)) {} };
I don't think I've tried it this way yet.
It works, but it's not efficient. It is even incredibly worse that doing the assignments by hand (boost 1.33.1 is better than 1.32 though). See my attached test program. Here is what I get (with g++ 4.1):
Try throwing this into the mix: a(boost::assign::cref_list_of<3>(1)(2)(3)) -Thorsten

Thorsten Ottosen wrote:
Sylvain Pion <Sylvain.Pion <at> sophia.inria.fr> writes:
Jeff Flinn wrote:
Would not the boost.assign library work here?
class A { boost::array<int, 3> a; A() : a(boost::assign::list_of(1)(2)(3)(4)) {} };
I don't think I've tried it this way yet.
It works, but it's not efficient. It is even incredibly worse that doing the assignments by hand (boost 1.33.1 is better than 1.32 though). See my attached test program. Here is what I get (with g++ 4.1):
Try throwing this into the mix:
a(boost::assign::cref_list_of<3>(1)(2)(3))
It gives the same result as the "assignment by hand", so it's still not optimal.
It would be nice to see what other compiler give back. Also, do you have full optimization turned on?
Optimizing or not does not change anything for the g++ I tested.
That said, list_of() is never going to compete with direct aggregrate initialization.
My point about introducing make_array() was also about syntax. The various Boost.Assign variants have poor syntax, imho, even if they could be optimized (I haven't looked at their implementation). I agree that the best thing would be to have a change in the language. But in the mean time, I think introducing make_array() in Boost.Array would be nice. I did not get feedback on that. -- Sylvain

Sylvain Pion wrote:
Thorsten Ottosen wrote:
Sylvain Pion <Sylvain.Pion <at> sophia.inria.fr> writes:
That said, list_of() is never going to compete with direct aggregrate initialization.
My point about introducing make_array() was also about syntax. The various Boost.Assign variants have poor syntax, imho, even if they could be optimized (I haven't looked at their implementation).
I agree that the best thing would be to have a change in the language. But in the mean time, I think introducing make_array() in Boost.Array would be nice. I did not get feedback on that.
I agree. I think this should go in the Array library, rather than boost.Assign. Alisdair, do you agree? -Thorsten

Thorsten Ottosen wrote:
I agree. I think this should go in the Array library, rather than boost.Assign.
Alisdair, do you agree?
It makes sense. I have thought about providing the functionality before, but didn't fancy getting on top of Boost PP to generate the overloads ;?) I will certainly look into this as something to do for Boost 1.35. In my ideal world, this would be spelled as make_tuple though, and tuples would be convertible to arrays. I don't think we can manage this in an acceptible manner without some changes to the initialization and POD rules. Actually, we could probably add a conversion operator to the tuple template, to convert to arrays. I am not sure that is such a great idea though. -- AlisdairM

AlisdairM wrote:
Thorsten Ottosen wrote:
I agree. I think this should go in the Array library, rather than boost.Assign.
Alisdair, do you agree?
It makes sense. I have thought about providing the functionality before, but didn't fancy getting on top of Boost PP to generate the overloads ;?)
I will certainly look into this as something to do for Boost 1.35.
Thanks Alisdair!
In my ideal world, this would be spelled as make_tuple though, and
Why? It seems to me that going through a tuple will force some copies, hence loose the efficiency.
tuples would be convertible to arrays. I don't think we can manage this in an acceptible manner without some changes to the initialization and POD rules.
Actually, we could probably add a conversion operator to the tuple template, to convert to arrays. I am not sure that is such a great idea though.
I don't have an opinion on this. -- Sylvain

Sylvain Pion <Sylvain.Pion <at> sophia.inria.fr> writes:
It works, but it's not efficient. It is even incredibly worse that doing the assignments by hand (boost 1.33.1 is better than 1.32 though). See my attached test program. Here is what I get (with g++ 4.1):
It would be nice to see what other compiler give back. Also, do you have full optimization turned on? That said, list_of() is never going to compete with direct aggregrate initialization. -Thorsten

I would like to use boost::array as a class data member.
This raises a problem when constructing it in the initialization list of the class members:
class A { boost::array<int, 3> a; A() : a(???) {} // what do I write here ??? };
Is there a way to construct the data member efficiently? By efficiently, I mean using copy constructors instead of default constructors followed by assignments of array elements.
This is not possible with the language today.
The following is possible today and appears to achieve what the OP asked for (but may not be what the OP wanted): class A { static boost::array<int, 3> s_a; boost::array<int, 3> a; public: A() : a(s_a) {} }; boost::array<int, 3> A::s_a = { 1, 2, 3 }; Sam

Sam Saariste wrote:
The following is possible today and appears to achieve what the OP asked for (but may not be what the OP wanted):
class A { static boost::array<int, 3> s_a; boost::array<int, 3> a; public: A() : a(s_a) {} }; boost::array<int, 3> A::s_a = { 1, 2, 3 };
My example code was only illustrative. The interesting case is that I want to pass the constructor arguments to the array. In which case your solution does not work. -- Sylvain
participants (6)
-
AlisdairM
-
Jeff Flinn
-
Sam Saariste
-
Sylvain Pion
-
Thorsten Ottosen
-
Thorsten Ottosen