If anyone could help me figure out WTH is going on here...
Alright, so it's complicated templates.
First, a snippet that shows where the problem occurs:
Code:
CCodeTokenGeneric* pToken = new CCodeTokenGeneric(CCodeToken::TOKEN_SPACE_INDENT);
ppnew<CCodeTokenGeneric> pToken2(pToken);
pp<CCodeToken/*Generic*/> pToken3(pToken2);
The third line is where the problem occurs. The compiler complains that I cannot create an instance of the abstract base class CCodeToken:
Code:
class CCodeToken abstract
Which by all means, it shouldn't be able to. However, that's not the problem, because I'm not instantiating an instance of the base class. I create a class derived from the base class, CCodeTokenGeneric:
Code:
class CCodeTokenGeneric: public CCodeToken
The actual compile error is:
Code:
error C3622: 'CCodeToken': a class declared as 'abstract' cannot be instantiated
see declaration of 'CCodeToken'
see reference to class template instantiation 'CMemoryManagerNew<T>' being compiled
with
[
T=CCodeToken
]
CMemoryManagerNew declaration is as follows:
Code:
template<typename T> class CMemoryManagerNew: public CMemoryManager<T>
{
public:
CMemoryManagerNew() throw(...);
CMemoryManagerNew(T* pNew) throw(...);
explicit CMemoryManagerNew(T NewValue) throw(...);
CMemoryManagerNew(const CMemoryManager<T>& rNew);
CMemoryManagerNew(const CMemoryManagerNew<T>& rNew);
CMemoryManagerNew(const CMemoryManagerNull& rNull);
CMemoryManagerNew(CMemoryManagerNull* pNull);
template<typename NewT> operator CMemoryManagerNew<NewT>& () const;
template<typename NewT> operator CMemoryManager<NewT>& () const;
//protected:
//CMemoryManagerNew(CMemoryManagerNew<T>& rmm) throw(...) { }
private:
CMemoryManagerNew(CMemoryManagerTimeCritical<T>&) { }
CMemoryManagerNew(CMemoryManagerTimeCriticalNew<T>&) { }
void operator = (CMemoryManagerTimeCritical<T>&) { }
void operator = (CMemoryManagerTimeCriticalNew<T>&) { }
};
The compile errors occurs on this line:
Code:
explicit CMemoryManagerNew(T NewValue) throw(...);
As to be expected. But what confuses me is that I do not have any code snippet that calls CMemoryManagerNew with type T = CCodeToken.
As you can see from the example, I create a new instance of CCodeTokenGeneric, which works fine. Then I store it inside a ppnew (CMemoryManagerNew) which also works fine.
But the problem comes when converting that CMemoryManagerNew to a CMemoryManager. This is expected to call the member function
Code:
template<typename NewT> operator CMemoryManager<NewT>& () const;
Which will return a reference to the same object but a different type. So it would return CMemoryManager<CCodeToken> so it can be embedded into the CMemoryManager object (pToken3).
I know it fails in this function, since if I comment out the line
Code:
explicit CMemoryManagerNew(T NewValue) throw(...);
And run the code, it calls this function as it should.
You might actually think that this is unsafe. That's why I use dynamic_cast internally to make sure the new type is compatible with the old. Here's the code for the
Code:
template<typename NewT> operator CMemoryManager<NewT>& () const;
Function:
Code:
return CMemoryManagerBase::TransformMemoryManager< NewT, CMemoryManager<NewT> >();
Which calls:
Code:
template<typename PtrType, typename FullType> FullType& TransformMemoryManager() const
{
PtrType* pTo = dynamic_cast<PtrType*>(p); // Security cast to make sure the new type in compatible with the old
ASSERT(pTo);
return *(FullType*)this;
}
Any help would be appreciated.
If anything is unclear, don't hesitate to ask.
EDIT:
Found the error.
The TransformMemoryManager function returns a reference of type CMemoryManager, which makes the compiler parse CMemoryManager<CCodeType>, but CMemoryManager in turn also has a constructor that takes a CMemoryManagerNew<T>, so when the compiler parses that it becomes CMemoryManagerNew<CCodeToken> and so the compiler parses CMemoryManagerNew with type T = CCodeToken and finds the constructor CMemoryManagerNew(T New) which translates to CMemoryManagerNew(CCodeToken New) which is illegal since it's abstract.
I guess to avoid headaches, I just remove the constructor. Any type can be initialized with its constructor anyway.