$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Aleksey Gurtovoy (agurtovoy_at_[hidden])
Date: 2005-01-12 04:55:18
Sergey Pisarchik writes:
>             Hello All,
>
> Problem is:
> what the difference between "type" in such cases?
>
> 1)
> class type{};
>
> and
>
> 2)
> class type1{};
> typedef type1 type;
>
> I think, they are equal. 
Almost:
1) In the second case, 'type' cannot be forward declared.
2) If 'type' used as a base class, the name injected into the
   derived class' scope will be different in each case:
   // case #1 
   struct type {};
   struct derived : type {};
   derived::type x; // OK
   // case #2
   struct type1 {};
   typedef type1 type;
   struct derived : type {};
   derived::type x; // Error, know nothing about 'type'!
   derived::type1 x; // OK, 'type1' is a base class.
> But... look code.
>
>
> /////////////////////////////////////
> //// Begin of code
> /////////////////////////////////////
>
> #include <boost\mpl\apply.hpp>
> #include <boost\mpl\lambda.hpp>
> #include <boost\mpl\placeholders.hpp>
> namespace mpl = boost::mpl;
>
> struct CClass{ void Init(int& i){i--;};};
>
> namespace impl
> {
>     template<typename TBase> struct CClass0:public TBase {
>     public:  void Init(int& i){i--; TBase::Init(i);};
>     };
>     template<typename TBase> struct CClass1:public TBase {
>     public:  void Init(int& i){i--;     TBase::Init(i);}
>     ;};
> }
>
> typedef mpl::lambda<impl::CClass0<mpl::_> >::type CClass0;
> typedef mpl::lambda<impl::CClass1<mpl::_> >::type CClass1;
>
> template <typename T1, typename T2> struct CMetaFunction1
> {
>         struct type1: public mpl::apply<T1, T2>::type{};
>         typedef type1 type;
> };
>
> template <typename T1, typename T2> struct CMetaFunction2
> {
>         struct type: public mpl::apply<T1, T2>::type{};
Unless you do want the resulting class hierarchy to be (literally)
   CMetaFunction2<
         CClass1
       , CMetaFunction2<CClass0, CClass>::type
       >::type
instead of:
    impl::CClass1< impl::CClass0<CClass> >
the above should become
          typedef typename mpl::apply<T1,T2>::type type;
Better, yet, get rid of 'CMetaFunction2' and use 'apply' directly.
Incidentally, either of these will also take care of the difference in
behavior you are seeing (see below for the explanation).
> };
>
> class CBase
> {
>         CBase(void)
>         {
>         {
>         CMetaFunction1<CClass1, CMetaFunction1<CClass0, CClass>::type
>>::type g;
>         int i=5;
>         g.Init(i);
>         }
>
> {
>         CMetaFunction2<CClass1, CMetaFunction2<CClass0, CClass>::type
>>::type g;
>         int i=5;
>         g.Init(i);
>         }        
>         }
> };
>
>
> ///////////////////////////////////////////////
> end of code
> //////////////////////////////////////////////
>
> Explanation:
> Want
>     impl::CClass1<impl::CClass0<CClass> >;
>
>     and running g.Init();
>     
>         CClass1::Init();
>         CClass0::Init();
>         CClass::Init();
>
> using CMetaFunction1 everything is OK.
> but CMetaFunction2 gives
>
>         CClass0::Init();
>         CClass::Init();
>
>
> WHY ???
Short answer: aforementioned use of inheritance in 'CMetaFunction2' +
base class name injection rules + MPL's "implict metafunction"
heuristic (http://www.boost.org/libs/mpl/doc/tutorial/lambda-and-non.html).
The following program illustrates the basics of what's happening in
your case:
    #include <boost/mpl/apply.hpp>
    #include <boost/mpl/assert.hpp>
    #include <boost/type_traits/is_same.hpp>
    using namespace boost;
    template< typename T > struct derived : T {};
    struct type {};
    // Error
    BOOST_MPL_ASSERT(( is_same< 
          mpl::apply< derived<mpl::_>, type >::type
        , derived<type>
        > ));
    // OK
    BOOST_MPL_ASSERT(( is_same< 
          mpl::apply< derived<mpl::_>, type >::type
        , type
        > ));
This at first surprising behavior is easy to understand once you
realize that 'derived<type>::type' is in fact a perfectly valid
expression designating, well, 'struct type {};'. Thus, for the
purpose of 'apply< derived<mpl::_>, type >::type' invocation,
'derived<mpl::_>' is an ordinary metafunction (as opposite to implicit
one) yelding 'type' -- as demonstrated by the asserts.
Correspondingly, an illustrative explanation for the behavior of your
original code is this:
    typedef CMetaFunction2<CClass0, CClass>::type class0;
    BOOST_MPL_ASSERT(( is_same<  // OK!
          CMetaFunction2< CClass1, class0 >::type
        , class0
        > ));
HTH,
-- Aleksey Gurtovoy MetaCommunications Engineering