template recursion in VC9
От: han2  
Дата: 25.06.13 13:46
Оценка: 39 (2)
Привет, народ.

Поясните, плз, почему указанный ниже код сомпилируется в VC7.1, но не компилируется в VC9, выдывая ошибку C3200 (и другие):


namespace aux {

    template< typename > struct unused;

    template<typename RootT, template< typename > class T0>
    struct TrimUnused
    {
        typedef T0<
            typename TrimUnused< RootT, unused >::Result
        > Result;
    };

    template< typename RootT >
    struct TrimUnused< RootT, unused >
    {
        typedef RootT Result;
    };
} // namespace aux

template< typename T > struct A : public T
{
    void check(char* p)
    {
        *p = 'A';
        T::check(++p);
    }
};

struct Root
{
    void check(char* p)
    {
        *p = 'R';
    }
};

//! Класс-наследник
struct D : public aux::TrimUnused< Root, A >::Result
{
    typedef aux::TrimUnused< Root, A >::Result _BaseT;

    void check(char* p)
    {
        *p = 'D';
        _BaseT::check(++p);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    char temp[32] = { 0 };
    D d;
    d.check(temp);

    return 0;
}
Re: template recursion in VC9
От: rg45 СССР  
Дата: 25.06.13 22:05
Оценка: 2 (1)
Здравствуйте, han2, Вы писали:

H>Привет, народ.


H>Поясните, плз, почему указанный ниже код сомпилируется в VC7.1, но не компилируется в VC9, выдывая ошибку C3200 (и другие):


H>
H>// . . .
H>//! Класс-наследник
H>struct D : public aux::TrimUnused< Root, A >::Result
H>{
H>    typedef aux::TrimUnused< Root, A >::Result _BaseT;

H>    void check(char* p)
H>    {
H>        *p = 'D';
H>        _BaseT::check(++p);
H>    }
H>};
H>// . . .
H>


Жаль, что из примера не понятно, какую роль играет эта замысловатость типов — ведь aux::TrimUnused< Root, A >::Result — это просто Root.

А вообще, похоже на еще один глюк студии. Интересно, что проблема устраняется простым вынесением определения типа _BaseT за пределы класса D. Также ошибка уходит при отказе от наследования D от aux::TrimUnused< Root, A >::Result (он же Root).
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: template recursion in VC9
От: han2  
Дата: 26.06.13 07:38
Оценка:
Здравствуйте, rg45, Вы писали:

R>Жаль, что из примера не понятно, какую роль играет эта замысловатость типов — ведь aux::TrimUnused< Root, A >::Result — это просто Root.


Это редуцированный до случая с T[N]=0, где N=0, пример реального шаблона, используемого для организации линейного наследования классов.

R> ведь aux::TrimUnused< Root, A >::Result — это просто Root.


Соответственно, aux::TrimUnused< Root, A >::Result — это, на самом деле A< Root >

R>А вообще, похоже на еще один глюк студии.


Если это ошибка, то она также есть и в VC10, которая выдаёт ту же ошибку при компиляции этого кода.

R>Интересно, что проблема устраняется простым вынесением определения типа _BaseT за пределы класса D.


Да, так и есть, проверил. Значит, скорее всего, ошибка VC.

R>Также ошибка уходит при отказе от наследования D от aux::TrimUnused< Root, A >::Result (он же Root).


По указанной выше причине (организация рекурсивного линейного наследования классов) это сделать не возможно, разве что перейти на использование boost::mpl::inherit_linearly.
Re: template recursion in VC9
От: Ku-ku  
Дата: 28.06.13 12:30
Оценка:
VC++9 честно следует правилам C++03.

typedef aux::TrimUnused< Root, A >::Result _BaseT;

Итогом поиска имени A будет ::A<Root>::A из базового класса, которое скрывает глобальное ::A.

В C++03 14.6.1 p1 говорится, что

Like normal (non-template) classes, class templates have an injected-class-name (clause 9). The injectedclass-
name can be used with or without a template-argument-list. When it is used without a templateargument-
list, it is equivalent to the injected-class-name followed by the template-parameters of the class
template enclosed in <>.

Поэтому ::A<Root>::A становится ::A<Root>::A<Root>, что уже не может использоваться как аргумент для template template parameter, о чём, собсно, VC++ и рапортует. Чтоб осчастливить компилятор, достаточно вместо A использовать ::A

typedef aux::TrimUnused< Root, ::A >::Result _BaseT;


В C++11 твой вариант узаконили
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1004

Насчёт реализации DR 1004 в новых версиях VC++ ничего сказать не могу.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.