Ошибочная / неверная ошибка C2248 при использовании Visual Studio 2010 - PullRequest
3 голосов
/ 18 мая 2010

Я вижу, что я считаю ошибочной / неправильной ошибкой компилятора при использовании компилятора Visual Studio 2010. Я нахожусь в процессе переноса нашей кодовой базы из Visual Studio 2005, и я наткнулся на конструкцию, которая раньше создавалась правильно, но теперь генерирует ошибку компилятора C2248.

Очевидно, что приведенный ниже фрагмент кода был обобщенным, но это скомпилированный пример сценария. Шаблон ObjectPtr<T> C ++ взят из нашей кодовой базы и является источником рассматриваемой ошибки. Кажется, что происходит, что компилятор генерирует вызов конструктора копирования для ObjectPtr<T>, когда это не должно происходить (см. Мой блок комментариев в методе SomeContainer::Foo() ниже). Для этой конструкции кода есть открытый оператор приведения для SomeUsefulData * в ObjectPtr<SomeUsefulData>, но он не выбирается внутри выражения true , если оператор ?:. Вместо этого я получаю две ошибки в приведенной ниже цитате блока.

Исходя из моих знаний C ++, этот код должен компилироваться. Кто-нибудь еще видел такое поведение? Если нет, может кто-нибудь указать мне на разъяснение правил разрешения компилятора, которое объясняет, почему в этом случае он пытается создать копию объекта?

Заранее спасибо,
Дилан Бурк

Вывод сборки Visual Studio:

c: \ projects \ objectptrtest \ objectptrtest.cpp (177): ошибка C2248: 'ObjectPtr :: ObjectPtr': невозможно получить доступ к закрытому члену, объявленному в классе 'ObjectPtr'
с
[T = SomeUsefulData]
c: \ projects \ objectptrtest \ objectptrtest.cpp (25): см. объявление ObjectPtr :: ObjectPtr
с
[T = SomeUsefulData]
c: \ projects \ objectptrtest \ objectptrtest.cpp (177): ошибка C2248: «ObjectPtr :: ObjectPtr»: невозможно получить доступ к закрытому члену, объявленному в классе «ObjectPtr»
с
[T = SomeUsefulData]
c: \ projects \ objectptrtest \ objectptrtest.cpp (25): см. объявление «ObjectPtr :: ObjectPtr»
с
[T = SomeUsefulData]


Ниже приведен минимальный компилируемый пример сценария:

#include <stdio.h>
#include <tchar.h>
template<class T>
class ObjectPtr {
public:
   ObjectPtr<T> (T* pObj = NULL, bool bShared = false) :
      m_pObject(pObj), m_bObjectShared(bShared)
   {}
   ~ObjectPtr<T> ()
   {
      Detach();
   }
private:
   // private, unimplemented copy constructor and assignment operator
   // to guarantee that ObjectPtr<T> objects are not copied
   ObjectPtr<T> (const ObjectPtr<T>&);
   ObjectPtr<T>& operator = (const ObjectPtr<T>&);
public:
   T * GetObject ()
      { return m_pObject; }
   const T * GetObject () const
      { return m_pObject; }
   bool HasObject () const
      { return (GetObject()!=NULL); }
   bool IsObjectShared () const
      { return m_bObjectShared; }
   void ObjectShared (bool bShared)
      { m_bObjectShared = bShared; }
   bool IsNull () const
      { return !HasObject(); }
   void Attach (T* pObj, bool bShared = false)
   {
      Detach();
      if (pObj != NULL) {
         m_pObject = pObj;
         m_bObjectShared = bShared;
      }
   }
   void Detach (T** ppObject = NULL)
   {
      if (ppObject != NULL) {
         *ppObject = m_pObject;
         m_pObject = NULL;
         m_bObjectShared = false;
      }
      else {
         if (HasObject()) {
            if (!IsObjectShared())
               delete m_pObject;
            m_pObject = NULL;
            m_bObjectShared = false;
         }
      }
   }
   void Detach (bool bDeleteIfNotShared)
   {
      if (HasObject()) {
         if (bDeleteIfNotShared && !IsObjectShared())
            delete m_pObject;
         m_pObject = NULL;
         m_bObjectShared = false;
      }
   }
   bool IsEqualTo (const T * pOther) const
      { return (GetObject() == pOther); }
public:
   T * operator -> ()
      { ASSERT(HasObject()); return m_pObject; }
   const T * operator -> () const
      { ASSERT(HasObject()); return m_pObject; }
   T & operator * ()
      { ASSERT(HasObject()); return *m_pObject; }
   const T & operator * () const
      {  ASSERT(HasObject()); return (const C &)(*m_pObject); }
   operator T * ()
      { return m_pObject; }
   operator const T * () const
      { return m_pObject; }
   operator bool() const
      { return (m_pObject!=NULL); }
   ObjectPtr<T>& operator = (T * pObj)
      { Attach(pObj, false); return *this; }
   bool operator == (const T * pOther) const
      { return IsEqualTo(pOther); }
   bool operator == (T * pOther) const
      { return IsEqualTo(pOther); }
   bool operator != (const T * pOther) const
      { return !IsEqualTo(pOther); }
   bool operator != (T * pOther) const
      { return !IsEqualTo(pOther); }
   bool operator == (const ObjectPtr<T>& other) const
      { return IsEqualTo(other.GetObject()); }
   bool operator != (const ObjectPtr<T>& other) const
      { return !IsEqualTo(other.GetObject()); }
   bool operator == (int pv) const
      { return (pv==NULL)? IsNull() : (LPVOID(m_pObject)==LPVOID(pv)); }
   bool operator != (int pv) const
      { return !(*this == pv); }
private:
   T * m_pObject;
   bool m_bObjectShared;
};

// Some concrete type that holds useful data
class SomeUsefulData {
public:
   SomeUsefulData () {}
   ~SomeUsefulData () {}
};

// Some concrete type that holds a heap-allocated instance of
// SomeUsefulData
class SomeContainer {
public:
   SomeContainer (SomeUsefulData* pUsefulData)
   {
      m_pData = pUsefulData;
   }
   ~SomeContainer ()
   {
      // nothing to do here
   }
public:
   bool EvaluateSomeCondition ()
   {
      // fake condition check to give us an expression
      // to use in ?: operator below
      return true;
   }
   SomeUsefulData* Foo ()
   {
      // this usage of the ?: operator generates a C2248
      // error b/c it's attempting to call the copy
      // constructor on ObjectPtr<T>
      return EvaluateSomeCondition() ? m_pData : NULL;
      /**********[ DISCUSSION ]**********
      The following equivalent constructs compile
      w/out error and behave correctly:

      (1) explicit cast to SomeUsefulData* as a comiler hint
      return EvaluateSomeCondition() ? (SomeUsefulData *)m_pData : NULL;

      (2) if/else instead of ?:
      if (EvaluateSomeCondition())
         return m_pData;
      else
         return NULL;

      (3) skip the condition check and return m_pData as a
          SomeUsefulData* directly
      return m_pData;
      **********[ END DISCUSSION ]**********/
   }
private:
   ObjectPtr<SomeUsefulData> m_pData;
};

int _tmain(int argc, _TCHAR* argv[])
{
   return 0;
}

Ответы [ 2 ]

2 голосов
/ 18 мая 2010

У конструкторов и деструкторов не должно быть параметров шаблона класса:

   ObjectPtr(T* pObj = NULL, bool bShared = false) :
      m_pObject(pObj), m_bObjectShared(bShared)
   {}

(обратите внимание на отсутствие <T>)

Но я думаю, что это не связано. Смотрите мой ответ ниже ...

1 голос
/ 18 мая 2010

У меня нет действительной копии стандарта C ++, но из этого черновика , стр. 102-103, утверждение неверно, если для expression ? E1 : E2 с типами T1 и T2 и если T1 и T2 не имеют отношения наследования, и один из них является r-значением, то

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

Кажется, это говорит о том, что ваше утверждение неправильно сформировано (поскольку у вас есть неявный конструктор ObjectPtr, а также operator T*), но, как я сказал, у меня нет действительного стандарта.

...