Boost logo

Boost Users :

Subject: Re: [Boost-users] Needs advices on design ( mpl or processor )
From: Allan Nielsen (a_at_[hidden])
Date: 2012-01-06 11:49:43


This is a much simple illustration of the problem I try to solve:

    template<int OFFSET>
    struct A {
        enum O { offset = OFFSET };
        enum S { size = 2 };
    };

    template<int OFFSET>
    struct B {
        enum O { offset = OFFSET };
        enum S { size = 4 };
    };

    template < typename B0, typename B1, typename B2 >
    struct C : public B0, B1, B2 {
    };

    int main(int argc, const char *argv[])
    {
        C< A<1>,

           B< A<1>::offset * A<1>::size >,

           A<
               B< A<1>::offset * A<1>::size >::offset *
               B< A<1>::offset * A<1>::size >::size
>
> c1;

        // does the same
        C< A<1>,

           B< A<1>::size >,

           A<
               A<1>::size *
               B< A<1>::size >::size
>
> c2;

        return 0;
    }

Is there a simpler way to let template arguments propagate through
derived classes?

On Fri, Jan 6, 2012 at 5:19 PM, Allan Nielsen <a_at_[hidden]> wrote:
> Hi
>
> This is not a specific questions directly related to Boost::mpl, but a request
> for help if somebody has the time...
>
> For the last couple of month I have been trying to learn to use the boost::mpl
> library.
>
> To learn to use the library I decided to use it for creating a
> "compressed-enum" library. The library should make it possible to store several
> enums in a single variable (for instance an unsigned int)
>
> Here is a simple example to give en idea:
>
> // example enums to play with
> struct TagA {
>    enum Size { size = 4 };
>    enum Max { max =  3 };
>    enum E { A0  =  0, A1  =  1, A2  =  2, A3  =  3, };
> };
> struct TagB {
>    enum Size { size = 4 };
>    enum Max { max =  3 };
>    enum E { B0  =  0, B1  =  1, B2  =  2, B3  =  3, };
> };
> struct TagC {
>    enum Size { size = 4 };
>    enum Max { max =  3 };
>    enum E { C0  =  0, C1  =  1, C2  =  2, C3  =  3, };
> };
>
> struct First{};
> struct Second{};
>
> int main() {
>    // using the compressed enums library
>    typedef unsigned short STORAGE;
>    typedef CompressedEnums< STORAGE,
>                             CompressedEnum<STORAGE,  1, TagA>,
>                             CompressedEnum<STORAGE,  4, TagB, First>,
>                             CompressedEnum<STORAGE, 16, TagB, Second>,
>                             CompressedEnumArray<STORAGE, 64, TagC, 5>
>                           > ENUMS;
>
>    assert(sizeof(ENUMS) == 2));
>    ENUMS enums;
>    enums.set<TagA>(TagA::A2);
>    enums.set<Second>(TagB::B2);
>    enums.set<3, TagC>(TagC::C2);
>
>    cout << enums.get<TagA>() << " " <<
>            enums.get<Second>(TagB::B2) << " " <<
>            enums.get<3, TagC>(TagC::C2) << endl;
> }
>
> CompressedEnums contains the storage variable, and inherit from all its
> template arguments, and make their methods available through tags.
> CompressedEnum and CompressedEnumArray only contains static methods which can
> find the enum in the storage variable.
>
> Here is a snippet of my implementation:
>
> template < typename STORAGE_TYPE,
>           int OFFSET,
>           typename ENUM_CONTAINER,
>           typename TAG = typename ENUM_CONTAINER::E
>         >
> struct CompressedEnum
> {
>    typedef TAG ACCESS_TAG;
>    typedef typename ENUM_CONTAINER::E INNER_TYPE;
>
>    enum Offset { offset = OFFSET };
>    enum Size { size = ENUM_CONTAINER::size };
>
>    static INNER_TYPE get(const STORAGE_TYPE& data) {
>        return (INNER_TYPE)((data / OFFSET) % size);
>    }
>
> ----%<----%<----%<----%<----%<----%<----%<----%<--
> }
>
> template < typename STORAGE_TYPE,
>           typename B00 = Dummy< 0>,
>           typename B01 = Dummy< 1>,
>           typename B02 = Dummy< 2>,
>           typename B03 = Dummy< 3>
>         >
> struct CompressedEnums : public B00, B01, B02, B03
> {
>    typedef boost::mpl::map<boost::mpl::pair<typename B00::ACCESS_TAG, B00>,
>                            boost::mpl::pair<typename B01::ACCESS_TAG, B01>,
>                            boost::mpl::pair<typename B02::ACCESS_TAG, B02>,
>                            boost::mpl::pair<typename B03::ACCESS_TAG,
> B03> > TYPE_MAP;
>
>    template<typename TAG>
>    typename boost::mpl::at<TYPE_MAP, TAG>::type::INNER_TYPE
>    get() const {
>        return boost::mpl::at<TYPE_MAP, TAG>::type::get(data);
>    }
>
> ----%<----%<----%<----%<----%<----%<----%<----%<--
>    STORAGE_TYPE data;
> };
>
>
> The code works and does what it is suppose to (as far as I know) but I'm not
> very happy with the interface:
>
> typedef CompressedEnums< STORAGE,
>
>                         // 1 because it is the first
>                         CompressedEnum<STORAGE,  1, TagA>,
>
>                         // 4 because TagA::size == 4
>                         CompressedEnum<STORAGE,  4, TagB, First>,
>
>                         // 16 because TagA::size * TagB::size == 16
>                         CompressedEnum<STORAGE, 16, TagB, Second>,
>
>                         // 64 because TagA::size * TagB::size *
> TagB::size == 64
>                         CompressedEnumArray<STORAGE, 64, TagC, 5>
>
>                       > ENUMS;
>
> These magic numbers makes it very easy to make bugs when the code is
> restructured or changed, and it should be possible to calculate them
> automatic. If the magic numbers are replaced with their expresions the
> code will still break of the arguemnts are reordered.
>
> To accomplice this I have considered two solutions: macro or more templating...
>
> Using macroes I imagin the interface could look something like this:
>
> typedef CompressedEnums< STORAGE,
>                         ENUM_PACK( STORAGE, 1,
>                                    (CompressedEnum, TagA)
>                                    (CompressedEnum, TagB, First)
>                                    (CompressedEnum, TagB, Second)
>                                    (CompressedEnumArray, TagC, 5) ) > ENUMS;
> Which then would expand to the code manual entered above.
>
> Alternative using template I imagin that CompressedEnums could change
> CompressedEnum<STORAGE, 0, TagB, Second> ->
> CompressedEnum<STORAGE, 16, TagB, Second>
> automatic and then derive from that one automatic.
>
> I tried both, but non of my idea worked out very well, which is why I
> hope that one of you c++ experts could give me some hints.
>
>
> Best regards
> Allan W. Nielsen


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net