Interest in a small array count facility?

Hi guys, a while ago there was some discussion about incorporating a compile-time array count facility in boost. I also provided an implementation for multidimensional arrays. Is there still interest for this? The benefits over the classical sizeof(array)/sizeof(array[0]) idiom are not overwhelming but at least there's a fair syntactical convenience and, of course, the advantage of unit test integration. If there's interest I can add it, to the utility subdirectory I guess (better suggestions are welcome; I really don't like using utility/ as a sort of repository for anything we have no better place for). --Gennaro.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
Hi guys,
a while ago there was some discussion about incorporating a compile-time array count facility in boost. I also provided an implementation for multidimensional arrays. Is there still interest for this? The benefits over the classical sizeof(array)/sizeof(array[0]) idiom are not overwhelming but at least there's a fair syntactical convenience and, of course, the advantage of unit test integration. If there's interest I can add it, to the utility subdirectory I guess (better suggestions are welcome; I really don't like using utility/ as a sort of repository for anything we have no better place for).
The biggest argument for such a mechanism is that it should be more foolproof. I hope it causes a compile error if "array" turns out to be a pointer. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Sun, 25 Jun 2006 11:37:51 -0400, David Abrahams <dave@boost-consulting.com> wrote:
The biggest argument for such a mechanism is that it should be more foolproof. I hope it causes a compile error if "array" turns out to be a pointer.
Yes, of course. I've reattached an implementation I proposed here a couple of years ago. The reason why I'm asking is basically that it would require some "somersault" to make it work with VC6 and other broken compilers, so I woldn't spend time on that if there is no interest. --Gennaro. begin 644 array_counter.hpp M+R\@+2T@87)R87E?8V]U;G1E<BYH<'`@+2T-"B\O#0HO+R`H0RD@1V5N;F%R M;R!0<F]T82`R,#`T#0HO+PT*+R\@(%5S92P@;6]D:69I8V%T:6]N+"!A;F0@ M9&ES=')I8G5T:6]N(&ES('-U8FIE8W0@=&\@=&AE($)O;W-T(%-O9G1W87)E M#0HO+R`@3&EC96YS92P@5F5R<VEO;B`Q+C`N("A3964@86-C;VUP86YY:6YG M(&9I;&4@3$E#14Y315\Q7S`N='AT(&]R(&-O<'D-"B\O("!A="!H='1P.B\O M=W=W+F)O;W-T+F]R9R],24-%3E-%7S%?,"YT>'0I#0HO+PT*+R\@("TM+2TM M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2T-"@T*(VEF M;F1E9B!-05E"15]"3T]35%]!4E)!65]#3U5.5$527TA04%]'4%\R,#`T,#$S M,`T*(V1E9FEN92!-05E"15]"3T]35%]!4E)!65]#3U5.5$527TA04%]'4%\R M,#`T,#$S,`T*#0HC:6YC;'5D92`\8W-T9&1E9CX-"@T*#0IN86UE<W!A8V4@ M;6%Y8F5?8F]O<W0@>PT*#0H@("`@=&5M<&QA=&4@/'-T9#HZ<VEZ95]T+"!T M>7!E;F%M93X-"B`@("!S=')U8W0@8V]U;G1?9&EM.PT*#0H@("`@=&5M<&QA M=&4@/'-T9#HZ<VEZ95]T(&1I;2P@='EP96YA;64@5"P@<W1D.CIS:7IE7W0@ M;CX-"B`@("!S=')U8W0@8V]U;G1?9&EM/&1I;2P@5%MN73X-"B`@("U8W0@8V]U M;G1?9&EM/#`L(%1;;ET^#0H@("`@>PT*("`@("`@("!S=&%T:6,@8V]N<W0@ M<W1D.CIS:7IE7W0@=F%L=64@/2!N.PT*("`@('T[#0H-"@T*("`@('1E;7!L M871E(#QS=&0Z.G-I>F5?="!D:6TL('1Y<&5N86UE(%0L('-T9#HZ<VEZ95]T M(&X^#0H@("`@8VAA<B`H)F%R<F%Y7V-O=6YT*%0H)BE;;ETI*2!;8V]U;G1? M9&EM/&1I;2P@5%MN73XZ.G9A;'5E73L-"@T*?0T*#0HC96YD:68@+R\@:6YC ,;'5D92!G=6%R9`T* ` end

On 6/25/06, Gennaro Prota <gennaro_prota@yahoo.com> wrote:
Yes, of course. I've reattached an implementation I proposed here a couple of years ago. The reason why I'm asking is basically that it would require some "somersault" to make it work with VC6 and other broken compilers, so I woldn't spend time on that if there is no interest.
The attachment didn't come out properly for me. I think it's worth including. It's not all that uncommon; even Freenode/##C++'s channel bot has the following factoid: Don't use sizeof() to get the size of an array, because sizeof() will do the wrong thing if that 'array' is actually a pointer. Use the following instead: template <typename T, size_t N> size_t array_size(T (&)[N]) { return N; } Of course that one only works for the outermost dimension of the array and I have no idea whether it works in VC6 at all.

On 6/25/06, me22 <me22.ca@gmail.com> wrote:
I think it's worth including. It's not all that uncommon; even Freenode/##C++'s channel bot has the following factoid: Don't use sizeof() to get the size of an array, because sizeof() will do the wrong thing if that 'array' is actually a pointer. Use the following instead: template <typename T, size_t N> size_t array_size(T (&)[N]) { return N; }
The downside of that is that it doesn't yield a compile-time constant, so you can't use it, for instance, as the size of another non-dynamically allocated array, nor for template metaprogramming, etc. For my projects, I do something like: #include <cstddef> namespace boost { template< typename Type, ::std::size_t Size > char (&array_size_impl( Type (&)[Size] ))[Size]; } #define BOOST_ARRAY_SIZE( array ) sizeof( ::boost::array_size_impl( array ) ) //////////////////////// The benefit of the above is that in addition to giving an easy-to-read compile-time an error when attempting to pass a pointer, it also yields a compile-time constant value. -- -Matt Calabrese

"Matt Calabrese" <rivorus@gmail.com> writes:
On 6/25/06, me22 <me22.ca@gmail.com> wrote:
I think it's worth including. It's not all that uncommon; even Freenode/##C++'s channel bot has the following factoid: Don't use sizeof() to get the size of an array, because sizeof() will do the wrong thing if that 'array' is actually a pointer. Use the following instead: template <typename T, size_t N> size_t array_size(T (&)[N]) { return N; }
The downside of that is that it doesn't yield a compile-time constant, so you can't use it, for instance, as the size of another non-dynamically allocated array, nor for template metaprogramming, etc.
That's very important.
For my projects, I do something like:
#include <cstddef>
namespace boost { template< typename Type, ::std::size_t Size > char (&array_size_impl( Type (&)[Size] ))[Size]; }
#define BOOST_ARRAY_SIZE( array ) sizeof( ::boost::array_size_impl( array ) )
Sold! -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 6/25/06 1:59 PM, "Matt Calabrese" <rivorus@gmail.com> wrote:
On 6/25/06, me22 <me22.ca@gmail.com> wrote:
I think it's worth including. It's not all that uncommon; even Freenode/##C++'s channel bot has the following factoid: Don't use sizeof() to get the size of an array, because sizeof() will do the wrong thing if that 'array' is actually a pointer. Use the following instead: template <typename T, size_t N> size_t array_size(T (&)[N]) { return N; }
The downside of that is that it doesn't yield a compile-time constant, so you can't use it, for instance, as the size of another non-dynamically allocated array, nor for template metaprogramming, etc. For my projects, I do something like:
#include <cstddef>
namespace boost { template< typename Type, ::std::size_t Size > char (&array_size_impl( Type (&)[Size] ))[Size]; }
#define BOOST_ARRAY_SIZE( array ) sizeof( ::boost::array_size_impl( array ) )
////////////////////////
The benefit of the above is that in addition to giving an easy-to-read compile-time an error when attempting to pass a pointer, it also yields a compile-time constant value.
In what I've read in this thread, I've never seen how to get the total count of elements in a multi-dimensional array. (I just seen how to get the count of a particular dimension.) How about something like: //======================================================================== template < typename T > struct array_element_count; template < typename T, std::size_t N > struct array_element_count< T[N] >; template < typename T > struct array_element_count { BOOST_STATIC_CONSTANT( std::size_t, count = 1u ); }; template < typename T, std::size_t N > struct array_element_count< T[N] > { BOOST_STATIC_CONSTANT( std::size_t, count = N * array_element_count<T>::count ); }; //======================================================================== Of course, this counts any non-array type as having an element count of 1. This may be handy in some circumstances, since the standard lets us treat a non-array object as an array of one element to allow iteration from "&x" to "&x + 1" to work. However, it seems the people here would prefer to make that case fail. (They want array-to-pointer conversions to fail an element count, and not count the pointer as itself.) What about: //======================================================================== template < typename T > struct array_element_count; template < typename T, std::size_t N > struct array_element_count< T[N] >; template < typename T > struct array_element_count { // Nothing here so non-array instantiations fail }; template < typename T, std::size_t N > struct array_element_count< T[N] > { private: template < typename U > struct array_element_count_impl; template < typename U, std::size_t M > struct array_element_count_impl< U[M] >; template < typename U > struct array_element_count_impl { BOOST_STATIC_CONSTANT( std::size_t, count = 1u ); }; template < typename U, std::size_t M > struct array_element_count_impl< U[M] > { BOOST_STATIC_CONSTANT( std::size_t, count = M * array_element_count_impl<U>::count ); }; public: BOOST_STATIC_CONSTANT( std::size_t, count = array_element_count_impl<T>::count ); }; //======================================================================== We do have to be careful of template instantiation depth. We finally add a function template wrapper to allow inductive sizing of array objects, and give errors on non-array objects, including pointers: //======================================================================== template < typename T, std::size_t N > char (&array_element_counter(T (&)[N]))[array_element_count<T[N]>::count]; #define BOOST_ARRAY_DEEP_COUNT( Array ) \ sizeof( array_element_counter((Array)) ) //======================================================================== -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

On Sat, 08 Jul 2006 19:30:13 -0400, Daryle Walker <darylew@hotmail.com> wrote:
In what I've read in this thread, I've never seen how to get the total count of elements in a multi-dimensional array. (I just seen how to get the count of a particular dimension.)
I never thought about this (or needed it). Did you? If there's consensus on introducing it I only see two problems: * choosing a good name :) * making it work on non-conforming compilers (I have to say of all compilers I tried my straightforward implementation on, only gcc could handle it, which is quite discouraging for such a trivial piece of code) -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

On 7/9/06 9:21 AM, "Gennaro Prota" <gennaro_prota@yahoo.com> wrote:
On Sat, 08 Jul 2006 19:30:13 -0400, Daryle Walker <darylew@hotmail.com> wrote:
In what I've read in this thread, I've never seen how to get the total count of elements in a multi-dimensional array. (I just seen how to get the count of a particular dimension.)
I never thought about this (or needed it). Did you?
No, I haven't considered or needed this either. I thought that the OP wanted a total element count, and no one in this thread actually answered that request. (They only considered the element count for a single dimension, where the "kewl" part was allowing any dimension to be measured.) Since every object of a multi-dimensional array is packed together, a total count could help in pointer-iterating the entire array as a single one-dimensional pass. The total count would help determine the end pointer, the beginning pointer would be made by reinterpret_cast-ing the address of the first element of the outermost array to an address of the first deep element. (They're the same type for a one-dimensional array, of course.)
If there's consensus on introducing it I only see two problems:
* choosing a good name :) * making it work on non-conforming compilers (I have to say of all compilers I tried my straightforward implementation on, only gcc could handle it, which is quite discouraging for such a trivial piece of code)
I typed that code directly into the e-mail client without ever compiling it. I am surprised by you saying a lot of compilers can't handle it. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

On Fri, 14 Jul 2006 06:52:51 -0400, Daryle Walker <darylew@hotmail.com> wrote:
On 7/9/06 9:21 AM, "Gennaro Prota" <gennaro_prota@yahoo.com> wrote:
[total count]
I never thought about this (or needed it). Did you?
No, I haven't considered or needed this either. I thought that the OP wanted a total element count, and no one in this thread actually answered that request.
I'm not sure we are in the same "thread". This one, "Interest in a small array count facility?", was started by me. Maybe you are referring to a question someone else asked in the past?
[...] I typed that code directly into the e-mail client without ever compiling it. I am surprised by you saying a lot of compilers can't handle it.
I didn't try your code either, but my original code, which is very similar, kills a lot of them. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

On Sun, 25 Jun 2006 13:11:32 -0400, me22 <me22.ca@gmail.com> wrote:
On 6/25/06, Gennaro Prota <gennaro_prota@yahoo.com> wrote:
Yes, of course. I've reattached an implementation I proposed here a couple of years ago. The reason why I'm asking is basically that it would require some "somersault" to make it work with VC6 and other broken compilers, so I woldn't spend time on that if there is no interest.
The attachment didn't come out properly for me.
Here's it, copy-and-pasted: // -- array_counter.hpp -- // // (C) Gennaro Prota 2004 // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy // at http://www.boost.org/LICENSE_1_0.txt) // // ------------------------------------------- #ifndef MAYBE_BOOST_ARRAY_COUNTER_HPP_GP_20040130 #define MAYBE_BOOST_ARRAY_COUNTER_HPP_GP_20040130 #include <cstddef> namespace maybe_boost { template <std::size_t, typename> struct count_dim; template <std::size_t dim, typename T, std::size_t n> struct count_dim<dim, T[n]> { static const std::size_t value = count_dim<dim-1, T>::value; }; template <typename T, std::size_t n> struct count_dim<0, T[n]> { static const std::size_t value = n; }; template <std::size_t dim, typename T, std::size_t n> char (&array_count(T(&)[n])) [count_dim<dim, T[n]>::value]; } #endif // include guard
I think it's worth including. It's not all that uncommon; even Freenode/##C++'s channel bot has the following factoid: Don't use sizeof() to get the size of an array, because sizeof() will do the wrong thing if that 'array' is actually a pointer. Use the following instead: template <typename T, size_t N> size_t array_size(T (&)[N]) { return N; }
That one has the advantage that it can be used without sizeof, but can't be used in constant expressions. My version is exactly the opposite in terms of pros/cons. Of course one can define a macro: #define BOOST_ARRAY_COUNT(a) ( sizeof array_count<0>(a) ) #define BOOST_ARRAY_COUNT_DIM(a, d) ...
Of course that one only works for the outermost dimension of the array and I have no idea whether it works in VC6 at all.
Oh, it doesn't :) Not even if you limit to one dimension. Even in that case it can't understand T(&)[N] and deduce T and N from that. But I'm not sure we should support VC6 more than with a sizeof/sizeof "fallback" version. BTW, I would like to make this work for std::tr1::array as well. --Gennaro.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
On Sun, 25 Jun 2006 11:37:51 -0400, David Abrahams <dave@boost-consulting.com> wrote:
The biggest argument for such a mechanism is that it should be more foolproof. I hope it causes a compile error if "array" turns out to be a pointer.
Yes, of course.
In that case, yes, it's very much worth including. Everytime I write sizeof(a)/sizeof(a[0]) I think "I know there's a better way to do this, but I don't have the time right now..." Libraries save us from that sort of cognitive dissonance when coding.
I've reattached an implementation I proposed here a couple of years ago. The reason why I'm asking is basically that it would require some "somersault" to make it work with VC6 and other broken compilers, so I woldn't spend time on that if there is no interest.
That somersault is easy enough (although I've forgotten what it was exactly, there's an easy workaround). -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Sun, 25 Jun 2006 17:43:26 -0400, David Abrahams <dave@boost-consulting.com> wrote:
That somersault is easy enough (although I've forgotten what it was exactly, there's an easy workaround).
Indeed I found it at the first try :) template <std::size_t n> struct counter { enum { n = n }; // yep :) template <typename t> static char(&count(t(*)[n]))[n]; }; #define COUNT_OF(x) \ (sizeof counter<(sizeof x / sizeof x[0])>::count(&x)) PS: note the enum! --Gennaro.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
On Sun, 25 Jun 2006 17:43:26 -0400, David Abrahams <dave@boost-consulting.com> wrote:
That somersault is easy enough (although I've forgotten what it was exactly, there's an easy workaround).
Indeed I found it at the first try :)
template <std::size_t n> struct counter { enum { n = n }; // yep :)
template <typename t> static char(&count(t(*)[n]))[n];
};
#define COUNT_OF(x) \ (sizeof counter<(sizeof x / sizeof x[0])>::count(&x))
PS: note the enum!
Wow, great! That trick is a new one to me. ...but is learning a new vc6 hack a virtue? -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Mon, 26 Jun 2006 11:26:57 -0400, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
[...]
template <std::size_t n> struct counter { enum { n = n }; // yep :)
template <typename t> static char(&count(t(*)[n]))[n];
};
#define COUNT_OF(x) \ (sizeof counter<(sizeof x / sizeof x[0])>::count(&x))
PS: note the enum!
Wow, great! That trick is a new one to me.
I'd say the more you can invent non-standard code the more chances you have to make VC6 "work" :) Of course the "n=n" above was just a whim on my part: if one uses two different names, such as "n" and "nn", the code is standard compliant. And you can also use directly a reference: t(&)[n]. So, not as bad as I was expecting. The real somersaults begin when you want the multidimensional case :) Here's what came out: template <std::size_t n> struct array_counter { enum { nn = n }; template <std::size_t d> struct dim { template <typename t, std::size_t sz> struct wrap { static t & expr; enum { n_ = sizeof(expr)/sizeof(expr[0]) }; enum { s = sizeof(array_counter<n_> ::dim<d-1>::count(expr).sizer ) }; char sizer [s]; }; template<typename t> static wrap<t, nn> count( t(&)[nn] ); }; template <> struct dim<0> { template <typename t, std::size_t sz> struct wrap { char sizer[sz]; }; template<typename t> static wrap<t, nn> count( t(&)[nn] ); }; }; #define COUNT_OF_N(d, x) \ sizeof(array_counter<sizeof(x)/sizeof(x[0])>::dim<d>::count(x).sizer) #include <ostream> #include <iostream> int main() { char a[1][2][3][4][5][6][7][8][9]; char a1[COUNT_OF_N(0, a)]; char a2[COUNT_OF_N(1, a)]; char a3[COUNT_OF_N(2, a)]; char a4[COUNT_OF_N(3, a)]; char a5[COUNT_OF_N(4, a)]; char a6[COUNT_OF_N(5, a)]; char a7[COUNT_OF_N(6, a)]; char a8[COUNT_OF_N(7, a)]; std::cout << sizeof(a1) << ", " << sizeof(a2) << ", " << sizeof(a3) << ", " << sizeof(a4) << ", " << sizeof(a5) << ", " << sizeof(a6) << ", " << sizeof(a7) << ", " << sizeof(a8) << '\n'; return 0; } ___ ___ PS: May Bjarne forgive us... ___ ___ --Gennaro.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
The real somersaults begin when you want the multidimensional case :) Here's what came out:
I'm pretty sure it's easier than this. IIRC, the macro can still do the old sizeof(a)/sizeof(a[0]) trick; it just needs to add something that will cause an error if a is not an array. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Wed, 28 Jun 2006 00:05:47 -0400, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
The real somersaults begin when you want the multidimensional case :) Here's what came out:
I'm pretty sure it's easier than this. IIRC, the macro can still do the old sizeof(a)/sizeof(a[0]) trick; it just needs to add something that will cause an error if a is not an array.
Sure that's easy for monodimensional arrays. When you write something like, for instance, COUNT_OF_N(3, x) though, it's not enough to check that x is an array. It shall be an array, x[0] shall be an array, x[1] and x[2] shall be arrays. I can imagine implementing it with some pp-lib iteration which automatically generates sizeof(x[0])/sizeof(x[0][0]) sizeof(x[0][0])/sizeof(x[0][0][0]) sizeof(x[0][0][0])/sizeof(x[0][0][0][0]) up to a given limit, but I'm not sure it can *reliably* be done with templates only. Suggestions are welcome. During my attempts I came out with some simpler solutions but they ICEd as soon as I invoked the macro in non trivial expressions. This is the solution which seemed more robust so far. FWIW, my opinion is that for VC6 we should only support the 1-dimensional case. --Gennaro.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
When you write something like, for instance,
COUNT_OF_N(3, x)
though, it's not enough to check that x is an array. It shall be an array, x[0] shall be an array, x[1] and x[2] shall be arrays. I can imagine implementing it with some pp-lib iteration which automatically generates
sizeof(x[0])/sizeof(x[0][0]) sizeof(x[0][0])/sizeof(x[0][0][0]) sizeof(x[0][0][0])/sizeof(x[0][0][0][0])
up to a given limit,
So what's wrong with that?
but I'm not sure it can *reliably* be done with templates only.
You need a macro anyway, don't you? -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Wed, 28 Jun 2006 08:55:11 -0400, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
When you write something like, for instance,
COUNT_OF_N(3, x)
though, it's not enough to check that x is an array. It shall be an array, x[0] shall be an array, x[1] and x[2] shall be arrays. I can imagine implementing it with some pp-lib iteration which automatically generates
sizeof(x[0])/sizeof(x[0][0]) sizeof(x[0][0])/sizeof(x[0][0][0]) sizeof(x[0][0][0])/sizeof(x[0][0][0][0])
up to a given limit,
So what's wrong with that?
Nothing. I didn't say it is wrong, just that I can't (still) see an easier template-only approach for the multidimentional case. It would help if you could post your simpler solution. With preprocessing manipulation I agree that you can have one function to detect arrays and do the actual computation with sizeof/sizeof.
but I'm not sure it can *reliably* be done with templates only.
You need a macro anyway, don't you?
You mean for the user? No. My idea was that the macro was provided as a shorthand (or maybe it wasn't provided at all --to be decided) but it was not "needed"; the user could anyway do: sizeof array_count<n>(arr) and that would give the count of the (n+1)-th dimension of arr. That should still be doable with my approach, even with VC6. Just to give the idea, it's enough to add something like this to my previous code: template <std::size_t d, typename t> struct vc6_wrap { static t & expr; enum { n_1 = sizeof(expr)/sizeof(expr[0]) }; enum { s = sizeof(array_counter<n_1> ::on_dim<d>::count(expr).result ) }; static char (&result) [s]; }; // "syntax adapter" template <std::size_t d, typename t> char(&array_count(t& a))[vc6_wrap<d, t>::s]; In my tests so far, this works: int main() { X a[1][2][3][4][5] = { 0 }; char a1[sizeof array_count<0>(a)] = { 0 }; // <-- char a2[sizeof array_count<1>(a)] = { 0 }; char a3[sizeof array_count<2>(a)] = { 0 }; char a4[sizeof array_count<3>(a)] = { 0 }; char a5[sizeof array_count<4>(a)] = { 0 }; std::cout << sizeof(a1) << ", " << sizeof(a2) << ", " << sizeof(a3) << ", " << sizeof(a4) << ", " << sizeof(a5) << '\n'; return 0; } but this doesn't: struct X { operator void*() const; double operator[](std::size_t) const; }; X x; sizeof array_count<0>(x); // no failure :-( --Gennaro.

Hello, Some time ago I mentioned on the list that I had a static sized version of valarray that I had been using locally and asked if there was any interest. I had been sidetracked by a new project so I just got around to cleaning up the docs and putting it into the vault. The code is "cvalarray". I do not do Windows development so I do not have access to any of the Microsoft compiler tools so I cannot test it on that platform. It is small enough that I believe portability should not be much of an issue issue. Any further interest or comments would be appreciated. Mike Tegtmeyer

Gennaro Prota <gennaro_prota@yahoo.com> writes:
Nothing. I didn't say it is wrong, just that I can't (still) see an easier template-only approach for the multidimentional case. It would help if you could post your simpler solution.
I never solved that problem... until today. The enclosed works. It could probably be considerably simplified if you untwist the logic a bit. In particular, you could probably find a way to get rid of remove_bounds. The basic idea here is that the only way to force an error in some contexts, with vc6, is at the top level, with eval0<...>::not_array being a nonexistent type. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Wed, 28 Jun 2006 23:38:25 -0400, David Abrahams <dave@boost-consulting.com> wrote:
Gennaro Prota <gennaro_prota@yahoo.com> writes:
Nothing.
Actually I implemented the pp-based solution yesterday. It's nice and absolutely error-proof. But there's a serious drawback. Can you see it off-hand? (I missed it, in advance, or I would have not written it)
I didn't say it is wrong, just that I can't (still) see an
easier template-only approach for the multidimentional case. It would help if you could post your simpler solution.
I never solved that problem... until today. The enclosed works. It could probably be considerably simplified if you untwist the logic a bit. In particular, you could probably find a way to get rid of remove_bounds. The basic idea here is that the only way to force an error in some contexts, with vc6, is at the top level, with eval0<...>::not_array being a nonexistent type.
I'll see what I'll come up with. Thanks for the hints. I like a lot the names, by the way: sizeof dimension<n>(a) is great :) --Gennaro.

On Wed, 28 Jun 2006 23:38:25 -0400, David Abrahams <dave@boost-consulting.com> wrote:
I never solved that problem... until today. The enclosed works. It could probably be considerably simplified if you untwist the logic a bit. In particular, you could probably find a way to get rid of remove_bounds. The basic idea here is that the only way to force an error in some contexts, with vc6, is at the top level, with eval0<...>::not_array being a nonexistent type.
Yes. As you say, "in some contexts". I realize that this is more an issue of compiler workarounds than template metaprogramming per se. I mean: you can get rid of remove_bounds<> and/or implement your is_array with something like this (not thoroughly tested): namespace xyz { // my usual conversion burning -gps struct burn { burn(const volatile void *); }; template <typename t> void is_array (t*, t* const volatile *); char is_array (burn ...); } Now, sizeof(xyz::is_array(e, &e)) should either produce an error or yield 1 (I may be missing something and the above might not work at all, but that's not the point). This is basically what I had used in my pp based solution, as, building upon, it you can easily generate for instance 1*1*1* sizeof(a[0][0]) / sizeof(a[0][0][0]) The point is: will xyz::is_array() do its job correctly in complex metaprogramming invocations? If you prefer "in all contexts"? A look at the mpl sources shows that they really make somersaults (well, let me use this word again :)) to hide compiler idiosyncracies (certainly our is_array<> is nothing as simple as the above). So, to make a long story short, I'm a bit reluctant to remove array_bounds<> or mpl::eval_if_c or anything else, because they are a thoroughly tested ground to build upon for broken compilers. And then all this *is* for broken compilers, as for conforming ones the whole utility is a few lines of code (my initial attachment). I'm refining your solution a bit and writing more tests, then if we agree on this I'll ask for a fast-track review. In the meantime I'd like to ask one question: * Any reason why you used mpl::identity<empty> instead of mpl::identity<>? does the latter break on some known compiler? I'm asking because it could be the reverse and that using the default (i.e. boost::mpl::na) is the preferred/most reliable way. My guess is that you just wanted to have a clearer diagnostic message, but I wanted to ask. --Gennaro.

Gennaro Prota <gennaro_prota@yahoo.com> writes:
* Any reason why you used mpl::identity<empty> instead of mpl::identity<>?
a. I didn't know identity had a default argument b. I'm not sure identity<> is supposed to be equivalent to identity<empty>
does the latter break on some known compiler? I'm asking because it could be the reverse and that using the default (i.e. boost::mpl::na) is the preferred/most reliable way.
My guess is that you just wanted to have a clearer diagnostic message, but I wanted to ask.
It doesn't help with the diagnostic. Either the nested thing fails to have a ::not_an_array member and you get an error, or it has the member and you don't. And, note, I didn't use ::type because that confuses the compiler with boost::type<...> and the resulting error message is less clear than it would be otherwise. Enclosed is one easy simplification step. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Thu, 29 Jun 2006 14:55:09 -0400, David Abrahams <dave@boost-consulting.com> wrote:
Enclosed is one easy simplification step.
Thanks. I'm now testing the very simple variation attached. What disturbs me with VC6 is that, either with the two versions you gave and with the one enclosed here, once you put the function template in the boost namespace you can't name it without qualification, despite a using boost::dimension; A using directive works but... Hoping this a known issue with a know workaround... --Gennaro. begin 644 Foo Blood Part III.hpp M+R\-"B\O($%R<F%Y(&-O=6YT97(-"B\O#0HO+R!!9&%P=&5D(&9R;VT@1&%V M92!!8G)A:&%M<R<@<V]L=71I;VX-"B\O#0HC:6YC;'5D92`\8W-T9&1E9CX- M"B\O(VEN8VQU9&4@(F)O;W-T+V-O;F9I9RYH<'`B("\O("TM9W!S#0H-"B-I M;F-L=61E(")B;V]S="]M<&PO979A;%]I9BYH<'`B#0HC:6YC;'5D92`B8F]O M<W0O;7!L+VED96YT:71Y+FAP<"(-"B-I;F-L=61E(")B;V]S="]T>7!E7W1R M86ET<R]I<U]A<G)A>2YH<'`B#0HC:6YC;'5D92`B8F]O<W0O='EP95]T<F%I M=',O<F5M;W9E7V)O=6YD<RYH<'`B#0H-"FYA;65S<&%C92!B;V]S="![#0H- M"FYA;65S<&%C92!D971A:6P@>R!N86UE<W!A8V4@87)R87E?8V]U;G0@>PT* M#0H@("`@=&5M<&QA=&4@/&-L87-S($$^#0H@("`@8VQA<W,@9&EM96YS:6]N M,`T*("`@('L-"B`@("`@("`@<W1A=&EC($$@83L@+R\@9&5F:6YI=&EO;B!N M;W0@<F5Q=6ER960@+2UA;F0@;F]T('=A;G1E9`T*("`@("`@("!E;G5M('ME M(#T@<VEZ96]F*&%;,%TI?3L-"B`@("!P=6)L:6,Z#0H@("`@("`@('1Y<&5D M968@8VAA<B`H)F%R<F%Y7W1Y<&4I6W-I>F5O9BA!*2]E73L-"B`@("!].PT* M#0H-"B`@("!T96UP;&%T92`\<W1D.CIS:7IE7W0@9"P@8VQA<W,@03X-"B`@ M("!C;&%S<R!C;W5N=&5R#0H@("`@>PT*("`@('!R:79A=&4Z("\O("TM9W!S M#0H-"B`@("`@("`@96YU;2O=6YD M<SQ!/CHZ='EP92!E;&5M96YT.PT*("`@("`@("!T>7!E9&5F('1Y<&5N86UE M(&UP;#HZ979A;%]I9E]C/`T*("`@("`@("`@("%D:0T*("`@("`@("`@("P@ M;7!L.CII9&5N=&ET>3P@9&EM96YS:6]N,#Q!/B`^#0H@("`@("`@("`@+"!C M;W5N=&5R/"!D:2TQ+"!E;&5M96YT(#X-"B`@("`@("`@/CHZ='EP92!C;W5N M=&5R7W1Y<&4[#0H-"B`@("!P=6)L:6,Z#0H-"B`@("`@("`@+R\@8VAE8VL@ M86YD(&9O<G=A<F0@=&\@8V]U;G1E<@T*("`@("`@("!T>7!E9&5F('1Y<&5N M86UE(&UP;#HZ979A;%]I9E]C/`T*("`@("`@("`@("`@(79A;&ED#0H@("`@ M("`@("`@("`L(&UP;#HZ:61E;G1I='D\=F]I9#X-"B`@("`@("`@("`@("P@ M;7!L.CII9&5N=&ET>3QC;W5N=&5R7W1Y<&4^#0H@("`@("`@(#XZ.G1Y<&4@ M='EP93L-"@T*("`@('T[#0H-"@T*("`@('1E;7!L871E(#QC;&%S<R!4/@T* M("`@('-T<G5C="!C:&5C:V5R,`T*("`@('L-"B`@("`@("`@='EP961E9B!T M>7!E;F%M92!4.CIA<G)A>5]T>7!E(&%R<F%Y7W1Y<&4[#0H@("`@?3L-"@T* M?7T@+R\@96YD(&1E=&%I;',-"@T*#0HO+R!M86EN(&9U;F-T:6]N+71E;7!L M871E#0HO+PT*=&5M<&QA=&4@/'-T9#HZ<VEZ95]T(&0L(&-L87-S(%0^#0IT M>7!E;F%M92!D971A:6PZ.F%R<F%Y7V-O=6YT.CIC:&5C:V5R,#P-"B`@("!T M>7!E;F%M92!D971A:6PZ.F%R<F%Y7V-O=6YT.CIC;W5N=&5R/&0L(%0^.CIT M>7!E#0H^.CIA<G)A>5]T>7!E(&1I;65N<VEO;BA4)BD[#0H-"GT@+R\@;F%M M97-P86-E(&)O;W-T#0H-"@T*#0H-"@T*+R\@;6EN:2UT97-T#0HC:6YC;'5D M92`\8W-T9&1E9CX-"B-I;F-L=61E(#QO<W1R96%M/@T*(VEN8VQU9&4@/&EO M<W1R96%M/@T*#0IS=')U8W0@6"![#0H@("`@='EP961E9B!I;G0J(&EN=%]P M='([#0H@("`@;W!E<F%T;W(@:6YT7W!T<B`H*2!C;VYS=#L-"B`@("!D;W5B M;&4@;W!E<F%T;W);72AS=&0Z.G-I>F5?="D@8V]N<W0[#0H@("`@:6YT7W!T M<B`J(&]P97)A=&]R)B@I(&-O;G-T.PT*?3L-"@T*#0II;G0@;6%I;B@I#0I[ M#0H-"B`@("!U<VEN9R!B;V]S=#HZ9&EM96YS:6]N.PT*#0H@("`@='EP961E M9B!8('AT6S-=6S5=6SA=6S$S75LR,5T[#0H@("`@>'0@83L-"B`@("`H=F]I M9"EA.PT*#0H@("`@8VAA<B!B.PT*("`@('-T871I8U]C87-T/'9O:60^*&(I M.PT*#0H@("`@8VAA<B!A,5MS:7IE;V8@9&EM96YS:6]N/#`^*&$I72`]('L@ M,"!].PT*("`@(&-H87(@83);<VEZ96]F(&1I;65N<VEO;CPQ/BAA*5T@/2![ M(#`@?3L-"B`@("!C:&%R(&$S6W-I>F5O9B!D:6UE;G-I;VX\,CXH82E=(#T@ M>R`P('T[#0H@("`@8VAA<B!A-%MS:7IE;V8@9&EM96YS:6]N/#,^*&$I72`] M('L@,"!].PT*("`@(&-H87(@835;<VEZ96]F(&1I;65N<VEO;CPT/BAA*5T@ M/2![(#`@?3L-"@T*(R!I9B!D969I;F5D($9!24Q?5$535%,-"B`@("!C:&%R M(&$V6W-I>F5O9B!D:6UE;G-I;VX\-3XH82E=(#T@>R`P('T[#0HC(&5N9&EF M#0H-"B`@("!S=&0Z.F-O=70@/#P@<VEZ96]F*&$Q*2`\/"`B+"`B(#P\('-I M>F5O9BAA,BD@/#P@(BP@(@T*("`@("`@("`@("`@("`\/"!S:7IE;V8H83,I M(#P\("(L("(@/#P@<VEZ96]F*&$T*2`\/"`B+"`B#0H@("`@("`@("`@("`@ M(#P\('-I>F5O9BAA-2D@/#P@)UQN)SL-"@T*("`@(')E='5R;B`P.PT*?0T* ` end

Gennaro Prota <gennaro_prota@yahoo.com> writes:
On Thu, 29 Jun 2006 14:55:09 -0400, David Abrahams <dave@boost-consulting.com> wrote:
Enclosed is one easy simplification step.
Thanks. I'm now testing the very simple variation attached. What disturbs me with VC6 is that, either with the two versions you gave and with the one enclosed here, once you put the function template in the boost namespace you can't name it without qualification, despite a
using boost::dimension;
A using directive works but... Hoping this a known issue with a know workaround...
It's just the way explicit template args work in vc6. You might need an alternative interface that allows the explicit passage of mpl::int_<d>(). Here's a version without remove_bounds. Unfortunately the diagnostic is poor in the case of failure. I'm out of time on this one, but maybe you can improve it. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Gennaro Prota wrote:
Sure that's easy for monodimensional arrays. When you write something like, for instance,
COUNT_OF_N(3, x)
Out of curiosity, have you ever needed this? I use the one-dimensional function all the time, but I've never, ever, needed to obtain "the 3rd size". By the way, Microsoft seems to be pushing _countof( x ) as a name for this functionality, probably with the intention to make it countof if it gets in an official C or C++ document one day. I've always used array_size or just size, but countof isn't bad.

On Wed, 28 Jun 2006 18:12:21 +0300, "Peter Dimov" <pdimov@mmltd.net> wrote:
Gennaro Prota wrote:
Sure that's easy for monodimensional arrays. When you write something like, for instance,
COUNT_OF_N(3, x)
Out of curiosity, have you ever needed this?
Shall I be sincere? No, I've never needed this :) But I generally invent a solution... then someone else comes out with the problem for it! Seriously, I feel it would be a bit inelegant on our part to just provide for the monodimensional case. Just my groundless impression perhaps...
I use the one-dimensional function all the time, but I've never, ever, needed to obtain "the 3rd size".
In all honesty, I think I've never really used statically sized arrays with more than 3 dimensions either (by the way, they tend to immediately grow out of stack possibilities; something like int x[3][4][5][6][7][8] would already take (8!)/(2!)*sizeof(int) bytes, thus typically 78.75 KiB, and the single dimension counts here are very low compared to what one could imagine for a "real life" application)
By the way, Microsoft seems to be pushing _countof( x ) as a name for this functionality, probably with the intention to make it countof if it gets in an official C or C++ document one day. I've always used array_size or just size, but countof isn't bad.
I've always chosen a name containing "count" rather than "size" because "size" implies or may imply "number of bytes", instead of "number of elements". _countof is nice but should be generalized, IMHO, even if multidimensional static arrays are rare. And I'd like for it to also work with tr1::array. --Gennaro.

I'm pretty sure it's easier than this. IIRC, the macro can still do the old sizeof(a)/sizeof(a[0]) trick; it just needs to add something that will cause an error if a is not an array.
So basically smth like: #define COUNT_OF(arr) BOOST_STATIC_ASSERT(boost::is_array<arr>::value); (sizeof(arr)/sizeof(arr[0])) ? Philippe p.s: not sure it actually works, just throwing ideas

Hum, actually it might be better to do it like : template <class Arr> struct count_of { BOOST_STATIC_ASSERT(boost::is_array<Arr>::value); enum { value = sizeof(Arr)/sizeof(Arr[0]) }; }; Sorry if I missed a point, joined late in the discussion :) Philippe

On Wed, 28 Jun 2006 15:31:07 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
Hum, actually it might be better to do it like :
template <class Arr> struct count_of { BOOST_STATIC_ASSERT(boost::is_array<Arr>::value); enum { value = sizeof(Arr)/sizeof(Arr[0]) }; };
Sorry if I missed a point, joined late in the discussion :)
The whole machinery is supposed to work with expressions, not type-ids, as you may see from my examples. And of course Arr[0] is not a valid type-id anyway. As you can see, though we have is_array I've basically to reimplement it. I've raised the point in the past that either is_array and other things such as is_convertible should work on expressions too, because this way they would most closely follow the language rules, and because you can easily implement the type-based versions in terms of the expression based ones but not viceversa. Unfortunately (or not, I'll leave it to you to decide) I've been totally ignored. At least, the second, IMHO compelling argument of implementability "in terms of", is completely omitted in the type_traits proposal. --Gennaro.
participants (8)
-
Daryle Walker
-
David Abrahams
-
Gennaro Prota
-
Matt Calabrese
-
me22
-
Michael Tegtmeyer
-
Peter Dimov
-
Philippe Vaucher