Re[4]: typedef vs public наследование
От: Ыукпун  
Дата: 12.01.05 12:20
Оценка: 15 (2)
Здравствуйте, MaximE, Вы писали:

ME>>>Во втором случае получается, что CClass1 не отнаследовался, что действительно странно. Запость в boost.devel.


Запостил. Кому интересно познакомьтесь.
Разбирался в ответе часа полтора-два, но зато получил огромное удовольствие когда понял причину.

Немного поменял постановку вопроса (в сторону упрощения понимания проблемы). Поэтому привожу мое письмо.

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;

///////////////////////////////////////////////


Ответ:

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


С уважением, Серега.

P.S. Не уверен, что можно постить такие длинные сообщения. Но не знаю как дать(найти на самом деле) ссылки на исходные письма.
Извиняюсь...
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Re: typedef vs public наследование
От: MaximE Великобритания  
Дата: 06.01.05 12:35
Оценка: 6 (2)
Здравствуйте, Ыукпун, Вы писали:

[]

Ы>[/ccode]


Ы>Соответствено при вызове Init() хочется получить последовательность действий:

Ы>CClass1.Init()
Ы>CClass0.Init()
Ы>CClass.Init()

Ы>При использовании fold разница только в метафункциях, а результат разный.


Ы>В первом случае все работает корректно

Ы>Во втором случае работает так:

Ы>CClass0.Init()

Ы>CClass.Init()

Ы>Может кто подскажет в чем причина?


Во втором случае получается, что CClass1 не отнаследовался, что действительно странно. Запость в boost.devel.
typedef vs public наследование
От: Ыукпун  
Дата: 06.01.05 11:43
Оценка:
а)        typedef CBase type;


б)        class type : publc CBase {};


По идее type в обоих случаях должен получиться одинаковым. И совпадать с CBase.

Проверил на двух компиляторах (VC++ 7.1 и GNU Dev-C++) следующий код:

#include <boost\mpl\apply.hpp>
#include <boost\mpl\list.hpp>
#include <boost\mpl\lambda.hpp>
#include <boost\mpl\fold.hpp>
#include <boost\mpl\int.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;

class ListOfTypes:public mpl::list<CClass0,CClass1>{};

template <typename T1, typename T2> struct CMetaFunction1
{
    struct type1: public mpl::apply<T2, T1>::type{};
    typedef type1 type;
};

template <typename T1, typename T2> struct CMetaFunction2
{
    struct type: public mpl::apply<T2, T1>::type{};
};

class CBase
{
public:
    CBase(void)
    {
        {
        mpl::fold<ListOfTypes, CClass, CMetaFunction1<mpl::_, mpl::_> >::type g;
        int i=5;
        g.Init(i);
        }
        {
        mpl::fold<ListOfTypes, CClass, CMetaFunction2<mpl::_, mpl::_> >::type g;
        int i=5;
        g.Init(i);
        }
    }
    ~CBase(void){};
};


// Пояснение 
// Есть шаблонные классы CClass0 и CCLass1.
// Шаблонный параметр используют как предка
// Все имеют функцию Init(int & i); которая вызывает такую же функцию у предка.
// 
// Цель, получить цепочку наследования
// 
// CClass1 <-  CClass0 <- CClass


Соответствено при вызове Init() хочется получить последовательность действий:
CClass1.Init()
CClass0.Init()
CClass.Init()

При использовании fold разница только в метафункциях, а результат разный.

В первом случае все работает корректно
Во втором случае работает так:

CClass0.Init()
CClass.Init()

Может кто подскажет в чем причина?
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Re: typedef vs public наследование
От: Анатолий Широков СССР  
Дата: 06.01.05 11:52
Оценка:
Здравствуйте, Ыукпун, Вы писали:

Ы>
Ы>а)        typedef CBase type;
Ы>


Ы>
Ы>б)        class type : publc CBase {};
Ы>


Ы>По идее type в обоих случаях должен получиться одинаковым. И совпадать с CBase.


Это ложный посыл. В первом случае да — type другое имя для CBase. Во втором же случае type это самостоятельный тип связанный с CBase лишь отношением наследования.
Re[2]: typedef vs public наследование
От: Ыукпун  
Дата: 06.01.05 12:45
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Здравствуйте, Ыукпун, Вы писали:


Ы>>
Ы>>а)        typedef CBase type;
Ы>>


Ы>>
Ы>>б)        class type : publc CBase {};
Ы>>


Ы>>По идее type в обоих случаях должен получиться одинаковым. И совпадать с CBase.


АШ>Это ложный посыл. В первом случае да — type другое имя для CBase. Во втором же случае type это самостоятельный тип связанный с CBase лишь отношением наследования.


Немного не так выразился.
Я хотел сказать в обоих случаях type должен обладать всеми свойствами, методами и т.п. которые есть у CBase.
Пользователь type не должен заметить разницы...
А она есть
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Re[2]: typedef vs public наследование
От: Ыукпун  
Дата: 06.01.05 13:27
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Во втором случае получается, что CClass1 не отнаследовался, что действительно странно. Запость в boost.devel.


Может сам запостишь?
Не знаю где это.
Заранее спасибо.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Re[2]: typedef vs public наследование
От: Ыукпун  
Дата: 06.01.05 13:32
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Здравствуйте, Ыукпун, Вы писали:


Ы>>
Ы>>а)        typedef CBase type;
Ы>>


Ы>>
Ы>>б)        class type : publc CBase {};
Ы>>


Ы>>По идее type в обоих случаях должен получиться одинаковым. И совпадать с CBase.


АШ>Это ложный посыл. В первом случае да — type другое имя для CBase. Во втором же случае type это самостоятельный тип связанный с CBase лишь отношением наследования.


Опечатался.
Так действительно разные..
Но у меня в коде написано:

Ы>а)        class type1 : public CBase{};
            typedef type1 type;


Ы>б)        class type : public CBase{};


Здесь type точно должен быть одним и тем же.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Re[3]: typedef vs public наследование
От: MaximE Великобритания  
Дата: 06.01.05 13:34
Оценка:
Здравствуйте, Ыукпун, Вы писали:

ME>>Во втором случае получается, что CClass1 не отнаследовался, что действительно странно. Запость в boost.devel.


Ы>Может сам запостишь?

Ы>Не знаю где это.

http://www.boost.org/more/mailing_lists.htm#main
Re[5]: typedef vs public наследование
От: c-smile Канада http://terrainformatica.com
Дата: 13.01.05 05:13
Оценка:
Здравствуйте, Ыукпун, Вы писали:

Вот! Тебе четким и понятным языком написали что
boost, а в особенности mpl использовать не надо.
Вылетит — не поймаешь.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.