Jaap Suter wrote: > Hi, Hi Jaap,
> I've written some MPL meta-functions that might be useful. But first a > question though... > > Is it possible that (under certain conditions) the following line: > > mpl::int_c< > mpl::minus< > mpl::int_c< 0 >, > mpl::int_c< 3 > > >::type::value > > > > has a different type than this one: > > mpl::minus< > mpl::int_c< 0 >, > mpl::int_c< 3 > > >::type Uhm, in fact, these are always different: typedef mpl::int_c< mpl::minus< mpl::int_c< 0 >, mpl::int_c< 3 > >::type::value > t1; typedef mpl::minus< mpl::int_c< 0 >, mpl::int_c< 3 > >::type t2; BOOST_STATIC_ASSERT((!boost::is_same<t1,t2>::value)); BOOST_STATIC_ASSERT((boost::is_same< t2 , mpl::integral_c<int,-3> >::value)); The motivation is that in ideal C++ word that has typedef templates all of the following assertions would be true, int_c<N> === integral_c<int,N> bool_c<C> === integral_c<bool,C> size_t_c<N> === integral_c<std::size_t,N> so the issue will go away by itself; another reason, of course, is that the current semantics was the simplest to implement ;). That's not to say that it should stay this way. Ideally, to support true mixed-type arithmetic, e.g. 'plus< rational<1,10>, int_c<5> >', the current MPL primitives such as 'plus', 'minus', 'multiply', etc. need a major re-write, to become something along these lines: template< typename N1 , typename N2 > struct plus { typedef typename promotion_traits<N1,N2>::type U_; typedef typename apply2< plus_traits<typename U_::tag> , typename construct<U_,N1>::type , typename construct<U_,N2>::type >::type type; }; template<> struct plus_traits<integral_c_tag> { template< typename N1, typename N2 > struct apply : integral_c< typename N1::value_type , (N1::value + N2::value) > { }; }; If we had this infrastructure in place, making 'minus< int_c<0>, int_c<3> >::type === int_c<-3>' would be trivial. Figuring out a reasonable way to specify the promotion rules is probably the hardest part there... > And now on to the good stuff... > > If you go to http://jaap.flipcode.com/boost/ you will find a > file called 'bit.zip'. In it are four files called: > > bit_and.hpp > bit_or.hpp > bit_xor.hpp > bit_shift_right.hpp > > I am using all of these in my own code currently, and they > work fine there. Wonderful! > Considering it's mostly copy paste work from the other > meta-functions, it shouldn't present any difficulties. I didn't > need the bit_shift_left meta function, so I haven't written > that one yet. Once discussions has settled, I'll be glad to add > that one too. > > Open issues: > > 1. I don't like the 'bit_' prefix, but there are already > logical 'and' and 'or' operators and corresponding files. One > option is to use 'bitwise' instead, but I liked the shortness of > 'bit'. IMO 'bit' is perfectly OK - in fact, the standard alternative tokens for & and | are called 'bitand' and 'bitor' correspondingly. What I am kind of ambivalent about is where to put the underscore, in the middle ('bit_and') or at the end ('bitand_'). I _think_ I prefer the latter, because, if applied consistently, it makes everything easier to remember: run-time compile-time void void_ sizeof sizeof_ &&, and and_ ||, or or_ !, not not_ &, bitand bitand_ |, bitor bitor_ BTW, I think 'bit_shift_right' should be named simply 'shift_right'; after all, may be someone would like to "overload" it :). > > 2, On my PC I've placed these files in the boost/mpl/bit > directory, just like boost/mpl/arithmetic and boost/mpl/logical > have their own directories. > Obviously, once dust has settled we need to make a 'bit.hpp' > that includes all the bit_* files, and place it in the MPL root. Actually, I was planning on bringing the content of "arithmetic", "logical", and "comparison" directories to "boost/mpl" root (still preserving the corresponding composite headers). In that light, I would suggest putting the new headers directly into the root directory as well. > 3. The bit_xor and bit_or functions are really simple. The > bit_and function however presented a problem for the default values > of parameters 3 to 5. I'm using 0xFFFFFFFF right now, which happens > to work on my (32 bit) platform, but obviously this is not a good > solution. Any suggestions are welcome. That's somewhat a part of the larger issue - on one hand, having arithmetic metafunctions accept more than two arguments definitely simplifies complex expressions: plus< N, M, int_c<10> > vs. plus< plus< N, M>, int_c<10> > On the other, the current way to implement it exposes a few problems; default arguments is one of them, but it's relatively easy to solve; a more serious one will be on our way as soon as we try to implement the architecture I've sketched at the beginning of the message. To solve these issues, I am inclining toward something like the following: template< typename N1 , typename N2 , typename N3 = void_ , typename N4 = void_ , typename N5 = void_ > struct plus : plus< typename plus< typename plus< typename plus<N1,N2>::type,N3 >::type,N4>::type, N5> { }; template< typename N1 , typename N2 , typename N3 , typename N4 > struct plus<N1,N2,N3,N4,void_> : plus< typename plus< typename plus< N1,N2>::type, N3>::type, N4> { }; // ... template< typename N1 , typename N2 > struct plus<N1,N2,void_,void_,void_> { // implementation }; So you can go this way, or just make everything take two operands only, and we'll take care of it later. > > 4. The interface for the bit_shift_right (and left) function should > be decided. Right now, the bit_shift_right_c function takes two types, > and two constants. However, I am not very knowledgable on what > operator >> and << are allowed to do according to the standard 5.8 [expr.shift]? :) > (For example, can the righthand operand be negative, "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." > when is a logical, bitwise or arithmetic shift performed, what if the lefthand operand > is negative, etc. etc.). Negative left-hand operands are allowed. We shouldn't worry about anything else since we just redirect to the built-in operators that do the right thing :). > The bit_shift_right (non _c) function just > takes two parameters as usual, and using AUX_TYPEOF their types are > passed to the bit_shift_right_c function (as with all the other > meta-functions). > Looks good to me! Aleksey _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost