
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. 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{}; }; 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 ??? Tested on VC++7.0 and GNU Dev-C++ P.S. when use my own lamda function Both variants works OK. /////////////////////////////////////////////// template <template <typename> class TBase> struct lambda { template <typename T> struct apply { typedef TBase<T> type; }; }; typedef lambda<impl::CClass0> CClass0; typedef lambda<impl::CClass1> CClass1; /////////////////////////////////////////////// --Sincerely Yours,-- --\ SergeY /-- --<>\\\ PisarchiK ///<>-- --<>()<>--Never surrendeR--<>()<>-- mailto:Sergey_pisarchiK@tut.by

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
participants (2)
-
Aleksey Gurtovoy
-
Sergey Pisarchik