Странная ошибка компиляции шаблонной специализации Singleton - PullRequest
2 голосов
/ 27 марта 2012

У меня проблема с шаблонами, которые используют класс и функцию в качестве параметров. Дело в том, что когда объявляется и определяется только AAInterceptor, он работает нормально. Когда я добавляю BBInterceptor, возникает ошибка компилятора, которая кажется довольно странной.

Вот код

template< class T>
class Singleton
{
protected:
    static T* ms_Singleton;
    Singleton()
    {
        if(!ms_Singleton)ms_Singleton = new T;
    }
public:
    static T& getSingleton( void ){assert( 0); return *ms_Singleton; }
};

struct InterceptorData
{
    unsigned int flag;

    InterceptorData():flag(0){}
};

template <class C, void (C::*TMethod)(const InterceptorData*)>
class InterceptorManager : public Singleton< InterceptorManager<C,TMethod> >
{

};

class AClass
{
public:
    virtual void Amethod(const InterceptorData* p_data = 0){};
};

class AAInterceptor : public InterceptorManager<AClass, &AClass::Amethod>
{
public:
    static AAInterceptor& getSingleton(void)
    {
        if (!ms_Singleton) new AAInterceptor();
        assert( ms_Singleton );  
        return ( *(static_cast< AAInterceptor*>(ms_Singleton)) );
    }
};

class BClass
{
public:
    virtual void Bmethod(const InterceptorData* p_data = 0){};
};

class BBInterceptor : public InterceptorManager<BClass, &BClass::Bmethod>
{
public:
    static BBInterceptor& getSingleton(void)
    {
        if (!ms_Singleton) new BBInterceptor();
        assert( ms_Singleton );  
        return ( *(static_cast< BBInterceptor*>(ms_Singleton)) );  //Here is the error of compilation
    }
};

int main(void)
{
    AAInterceptor a;
    BBInterceptor b;
    return 0;
}

Прекрасно компилируется с GCC (http://codepad.org/Bi6zbsmq),, но не с MSVC2008.

А вот ошибка в Visual Studio:

error:  " error C2440: 'static_cast' : cannot convert from 'InterceptorManager<C,TMethod> *' to 'BBInterceptor *' " 58
with
1>        [
           1>            C=BClass,
           1>            TMethod=void AClass::`vcall'{0}'(const InterceptorData *)
           1>        ]
1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

Кажется, компилятор смешивает разные шаблоны, не так ли?

Заранее спасибо за помощь

1 Ответ

3 голосов
/ 31 марта 2012

Этот код не вызывает ошибку компилятора, просто поместите виртуальный вызов в не-виртуальную функцию и получите ее адрес.

template<typename T>
class Singleton
{
protected:
  static T* ms_Singleton;
  Singleton()
  {
    if(!ms_Singleton)ms_Singleton = new T;
  }
public:
  static T& getSingleton( void ){assert(0); return *ms_Singleton; }
};

template<typename T>
T* Singleton<typename T>::ms_Singleton = 0;

struct InterceptorData
{
  unsigned int flag;
  InterceptorData():flag(0){}
};

template <typename C, void (C::*TMethod)(const InterceptorData*)>
class InterceptorManager : public Singleton< InterceptorManager<C,TMethod> >
{
};

class AClass
{
public:
  void Amethod(const InterceptorData* p_data = 0){AmethodImpl(p_data);};
  virtual void AmethodImpl(const InterceptorData* p_data = 0){};
};

class AAInterceptor : public InterceptorManager<AClass, &AClass::Amethod>
{
public:
  static AAInterceptor& getSingleton(void)
  {
    if (!ms_Singleton) new AAInterceptor();
    assert( ms_Singleton );  
    return ( *(static_cast< AAInterceptor*>(ms_Singleton)) );
  }
};

class BClass
{
public:
  void Bmethod(const InterceptorData* p_data = 0){BmethodImpl(p_data);};
  virtual void BmethodImpl(const InterceptorData* p_data = 0){};
};

class BBInterceptor : public InterceptorManager<BClass, &BClass::Bmethod>
{
public:
  static BBInterceptor& getSingleton(void)
  {
    if (!ms_Singleton) new BBInterceptor();
    assert( ms_Singleton );  
    return ( *(static_cast< BBInterceptor* >(ms_Singleton)) );  
  }
};

int main(void)
{
  AAInterceptor a;
  BBInterceptor b;
  return 0;
}
...