crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в Еще одна ошибка компилятора
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
Tonal Дата 7.12.2007, 11:52
  Зачем прибавляет - понятно - в ATemplateBase указатель this смещён относительно VS8ErrorClass.
Почему дважды - тоже понятно - первый раз - смещение ATemplateBase относительно обшего, второй смещение i относительн ATemplateBase в общем.

Формально всё правильно, ведь sizeof любого класса > 0 и равен текущему выравниванию.

Ошибается оно, похоже на "оптимизации базовых классов": стандартом разрешено не увеличивать размер в случае наследования от "пустого" класса. Пустым будет класс не содержащий данных членов, виртуальных функций и виртуального наследования не в себе не в своих предках.

Похоже эта оптимизация производиться, но не во всех случаях корректно отрабатывают преобразования для this.

Проверить это можно поиграв размерами и пустотой классов ATemplateBase и EatMe
Ну и обход понятен, если так- добавить фиктивный член в ATemplateBase.
LuckLess Дата 7.12.2007, 11:32
 
Цитата(Tonal @ 6.12.2007, 11:02) *
P.S. ошибка, которая вылезает в VC8 похоже связана не с этим а с выравниванием - где то он похоже путается.
Если EatMe убрать из предков, что получится? А если поменять его местами с ATemplateBase?

Студия просто прибавляет двойное смещение к this-у для базового класса зачемто. Смотрел в асме даже :p
Если базовый класс будет первыйм то двойное смещение будет 0 == 0*2 и все будет ок :D
Tonal Дата 6.12.2007, 10:02
  Такое и не должно компилироваться, из за
...
  void foo ()
      {
      ATemplateBase::foo ();
      }
...

Здесь, по стандарту, должна быть явная классификация шаблона.
У VC это довольно старая бага.
Там таких полно: я когда их движёк регэкспов (гретту) попробывал использовать под gcc там подобные глюки пачками сыпались. А часто и более замысловатые.

Эта та проблема довольно просто решается:
...
class VS8ErrorClass : public EatMe, public ATemplateBase<VS8ErrorClass>
   {
typedef ATemplateBase<VS8ErrorClass> ATemplateBase;
public:
...


P.S. ошибка, которая вылезает в VC8 похоже связана не с этим а с выравниванием - где то он похоже путается.
Если EatMe убрать из предков, что получится? А если поменять его местами с ATemplateBase?
LuckLess Дата 19.10.2007, 10:47
  нуу.. опять начну с кода...
template <class T>
class ATemplateBase
   {
public:
   void foo ()
      {
      static_cast<T*> (this)->i = 666;
      }
   };

class EatMe//:P
   {
   char m[4];
   };

class VS8ErrorClass : public EatMe, public ATemplateBase<VS8ErrorClass>
   {
public:
   VS8ErrorClass () : i (0)
      {

      }

   void foo ()
      {
      ATemplateBase::foo ();
      }

   int i;
   };


int main ()
   {
   struct FunnyStruct
      {
      VS8ErrorClass error;
      int devilsNumber;

      FunnyStruct () : devilsNumber (0)
         {

         }
      };
  
   FunnyStruct fs;
   std::cout << fs.error.i << " " <<  fs.devilsNumber << "\n";
   fs.error.foo ();
   std::cout << fs.error.i << " " <<  fs.devilsNumber << "\n";
   }


ну... вопервых почему этот код превельный..
static_cast<T*> должен сработать т.к.
Цитата
An rvalue of type “pointer to cv1 B,” where B is a class type, can be converted to an rvalue of type “pointer to cv2 D,”
where D is a class derived (clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists
(4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is not a virtual base class of D.


самое сложное тут ATemplateBase::foo ();
фактически такой вызов должен срботать т.к. есть такая штука как injected class name
Цитата
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name
is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access
checking, the injected-class-name is treated as if it were a public member name.

Цитата
In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the
base class in the scope in which it was declared.

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

так что ATemplateBase::foo (); нормальный вызов т.к. ATemplateBase это injected class name который
можно использовать без шаблонных параметров.

Вот.. собстно эффект от этого кода... в 8-й студии все очень плохо... переменная devilsNumber зачемто равно 666 ))).
Одна из гцц нескомпилировала это дело.. что тоже плохо.. но заметно лучше чем результат студии

как избавится от этого...? просто использовать injected-class-name с шаблонными параметрами.
ATemplateBase<VS8ErrorClass>::foo ();

техника такого статик каста прменяется во многих ATL-ых базовых классах.. и бывает краайне неудобно
вызывать их метод полностью выписывая шаблонные параметры, так как их там часто очень много :D

ждем второго сервис пака к студии?))
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 29.3.2024, 17:45