Why isn't this template being instantiated?

G

Guest

This code get's a link error (I'm guessing because the template isn't being
instantiated)...

// For using templates to simplify deleting items
template <class T>
// Returns the next ADHL in the list
AbstractDataHolderList*
// Used to delete this object and the item it points to
AbstractDataHolderList::DeleteThisItem(void)
{
// do stuff to update list (since this item is being removed)

delete (typename T*)m_thisItem;
delete this;

return m_nextADHL;
}

/* ... */ main (/* ... */)
{
/*****************************************
* We make some items (CString in this case?)
* and add em to the list, then run the program up here
*****************************************/

// This part is the important thing
while (myADHL != NULL)
myADHL = myADHL->DeleteThisItem<CString>();

return 0;
}

If I change the DeleteThisItem method in the ADHL class to be the
instanciated template for a CString (ie:
"/*...*/::DeleteThisItem<CString>(void)"), then there isn't a linking error.
But I'm wondering why the compiler doesn't notice that main is calling the
template with a forced type of CString. Shouldn't the call in main force an
instanciation of the template with T = CString? (as a side note... since
there are no parameters, if <CString> is omited in the DeleteThisItem call,
then this code doesn't even compile, because the type cannot be
determined... which is why i'm wondering, when I say that the type is a
CString, why isn't the CString version of the template created?)
 
V

Victor Bazarov

This code get's a link error (I'm guessing because the template isn't being
instantiated)...

// For using templates to simplify deleting items
template <class T>
// Returns the next ADHL in the list
AbstractDataHolderList*
// Used to delete this object and the item it points to
AbstractDataHolderList::DeleteThisItem(void)
{
// do stuff to update list (since this item is being removed)

delete (typename T*)m_thisItem;
delete this;

return m_nextADHL;
}

/* ... */ main (/* ... */)
{
/*****************************************
* We make some items (CString in this case?)
* and add em to the list, then run the program up here
*****************************************/

// This part is the important thing
while (myADHL != NULL)
myADHL = myADHL->DeleteThisItem<CString>();

return 0;
}

If I change the DeleteThisItem method in the ADHL class to be the
instanciated template for a CString (ie:
"/*...*/::DeleteThisItem<CString>(void)"), then there isn't a linking error.
But I'm wondering why the compiler doesn't notice that main is calling the
template with a forced type of CString. Shouldn't the call in main force an
instanciation of the template with T = CString? (as a side note... since
there are no parameters, if <CString> is omited in the DeleteThisItem call,
then this code doesn't even compile, because the type cannot be
determined... which is why i'm wondering, when I say that the type is a
CString, why isn't the CString version of the template created?)

The name CString suggests that you're using Visual C++. Is it by any
chance VC++ v6? Then you need a work-around:

template <class T>
// Returns the next ADHL in the list
AbstractDataHolderList*
// Used to delete this object and the item it points to
AbstractDataHolderList::DeleteThisItem(T* = 0)

By introducing the argument of the same type as you're trying to get the
template to use you can trick the compiler into recognising the need to
instantiate the template correctly.

I am not actually sure about this work-around, do check with the VC++
newsgroup: microsoft.public.vc.language.

Victor
 
G

Guest

The name CString suggests that you're using Visual C++. Is it by any
chance VC++ v6? Then you need a work-around:

template <class T>
// Returns the next ADHL in the list
AbstractDataHolderList*
// Used to delete this object and the item it points to
AbstractDataHolderList::DeleteThisItem(T* = 0)

By introducing the argument of the same type as you're trying to get the
template to use you can trick the compiler into recognising the need to
instantiate the template correctly.

I am not actually sure about this work-around, do check with the VC++
newsgroup: microsoft.public.vc.language.

Victor

Thanks for the info... so I guess in gcc, and other compilers this isn't
necessarily an issue? Other compilers figure this stuff out for me? (mines
..NET... so I guess m$ hasn't tried fixing this yet...) I just ended up doing
this:

template < >
// Returns the next ADHL in the list
AbstractDataHolderList*
// Used to delete this object and the CString item it points to
AbstractDataHolderList::DeleteThisItem < CString > (void)

for each type that I need to delete, as an added bonus I add one for "void"
which doesn't delete the item... just incase I find good reason to do
that... Well... if it's a VC++ ... feature ... 0.o then i'll just member
that I'm smart and they... are... well... thier smart too... but... I'm
SMARTER! ;)

Thanks,
Dead RAM
 
V

Victor Bazarov

Thanks for the info... so I guess in gcc, and other compilers this isn't
necessarily an issue? Other compilers figure this stuff out for me? (mines
.NET... so I guess m$ hasn't tried fixing this yet...) I just ended up doing
this:

template < >
// Returns the next ADHL in the list
AbstractDataHolderList*
// Used to delete this object and the CString item it points to
AbstractDataHolderList::DeleteThisItem < CString > (void)

for each type that I need to delete, as an added bonus I add one for "void"
which doesn't delete the item... just incase I find good reason to do
that... Well... if it's a VC++ ... feature ... 0.o then i'll just member
that I'm smart and they... are... well... thier smart too... but... I'm
SMARTER! ;)

I may have misinterpreted the situation, sorry about that. The .NET (is
that 7.1?) compiler is far more advanced than v6 when the templates are
concerned.

Since you didn't post the complete code, I couldn't verify the error on
any of the compilers available to me here, so I probably fell into
assuming too much. Try this:
----------------------------------
struct CS {}; // my version of "CString"
struct A { // my version of your "AbstractDataHolderList"
template<class T> A* foo(); // my "DeleteThisItem"
};

template<class T> A* A::foo() { // definition
T t;
return this;
}

int main() {
A a;
A* pa = &a;
pa = pa->foo<CS>();
}
 
G

Guest

I may have misinterpreted the situation, sorry about that. The .NET (is
that 7.1?) compiler is far more advanced than v6 when the templates are
concerned.

Since you didn't post the complete code, I couldn't verify the error on
any of the compilers available to me here, so I probably fell into
assuming too much. Try this:
----------------------------------
struct CS {}; // my version of "CString"
struct A { // my version of your "AbstractDataHolderList"
template<class T> A* foo(); // my "DeleteThisItem"
};

template<class T> A* A::foo() { // definition
T t;
return this;
}

int main() {
A a;
A* pa = &a;
pa = pa->foo<CS>();
}

Thanks for that info... It didn't solve my problem, but it made me
recognize that I was the one with the error... and not the
compiler/linker... (as is always the case... >.<)

I had my template declairation in a header file:

template <class T> ADHL* DelThis();

which was included with all the code that used the class ADHL but the
definition:

template <class T> ADHL* ADHL::DelThis()
{
// Code goes here...
}

was in a separate cpp file... so the compiler never knew about the work the
template was doing until it was too late... Which I'm guessing is a good
type of error to generate (forces people to put templates in headers...
since they are not code in and of themselves).

Thanks for all the help Victor ;) I'd be lost without it 0.o
 
V

Victor Bazarov

Thanks for that info... It didn't solve my problem, but it made me
recognize that I was the one with the error... and not the
compiler/linker... (as is always the case... >.<)

I had my template declairation in a header file:

template <class T> ADHL* DelThis();

which was included with all the code that used the class ADHL but the
definition:

template <class T> ADHL* ADHL::DelThis()
{
// Code goes here...
}

was in a separate cpp file... so the compiler never knew about the work
the template was doing until it was too late... Which I'm guessing is a
good type of error to generate (forces people to put templates in
headers... since they are not code in and of themselves).

You could do this special thing in your separate cpp file: add explicit
instantiations. After the definition of the template member add lines
like these:

template ADHL* ADHL::DelThis<CSting>();
template ADHL* ADHL::DelThis<int>();

and so on, for all types you think are relevant. The compiler will have
to generate all the instantiations mentioned. It usually leads to code
bloat, but it does help hide the implementation, besides if your template
is intended to work only with a limited set of types, it's not such a bad
deal.

Victor
 
M

Malte Starostik

This code get's a link error (I'm guessing because the template isn't being
instantiated)...

// For using templates to simplify deleting items
template <class T>
// Returns the next ADHL in the list
AbstractDataHolderList*
// Used to delete this object and the item it points to
AbstractDataHolderList::DeleteThisItem(void)
{
// do stuff to update list (since this item is being removed)

delete (typename T*)m_thisItem;
delete this;

return m_nextADHL;

On a side note, the above line looks suspiciously like you're shooting
yourself in the foot there. Assuming m_nextADHL is a member of this,
you must not use it anymore, as this it's no longer valid. To return a
data member's value you need to make a local copy before committing
suicide and then return that copy's value. No more accessing non-static
data members or calling non-static member functions or anything else
that involves the this pointer after self-destruction. Ever.

Regards,
Malte

PS: While such drastic consequences of dereferencing invalid pointers
are unlikely in today's OSs unless you're hacking the kernel, I actually
once killed half of my file system with something like that under DOS...
 
G

Guest

You could do this special thing in your separate cpp file: add explicit
instantiations. After the definition of the template member add lines
like these:

template ADHL* ADHL::DelThis<CSting>();
template ADHL* ADHL::DelThis<int>();

and so on, for all types you think are relevant. The compiler will have
to generate all the instantiations mentioned. It usually leads to code
bloat, but it does help hide the implementation, besides if your template
is intended to work only with a limited set of types, it's not such a bad
deal.

Victor

I like that idea, keeps the code clean enough ;) thanks for the tips ;)
 
G

Guest

On a side note, the above line looks suspiciously like you're shooting
yourself in the foot there. Assuming m_nextADHL is a member of this, you
must not use it anymore, as this it's no longer valid. To return a data
member's value you need to make a local copy before committing suicide and
then return that copy's value. No more accessing non-static data members
or calling non-static member functions or anything else that involves the
this pointer after self-destruction. Ever.

Regards,
Malte

PS: While such drastic consequences of dereferencing invalid pointers are
unlikely in today's OSs unless you're hacking the kernel, I actually once
killed half of my file system with something like that under DOS...

That was once a error for me, but I fixed that long ago... just showed up in
this code due to lazyness ^.~ What I do is make a local ADHL pointer, then
find out what it should point to (pMyPointer = m_nextItem for example...)
then return the pointer to the next, or previous ADHL... or sometimes NULL.
But thanks for the tip... can never be too safe when it comes to playing
with pointers and delete and such ;)

As a side note... I once blew up a palm pilot screen doing something like
this ;) ok... ok... I only made it go "pop" and only a 4x160 pixel area on
the screen doesn't get drawn... So yah... this stuff is bad to do... thanks
for the reminder ;)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top