Click to See Complete Forum and Search --> : Using a template function as for_each "argument" = unresolved external symbol error


PaulWendt
February 26th, 2003, 07:59 AM
Hello,

I tried to make the subject intuitive. Anyway, as described, I'm
trying to use a template function as the function argument for
for_each(). In particular, I'm trying to use boost's checked_delete
in an attempt to basically delete every member in a vector of
pointers [who each point to dynamically allocated memory].

Yeah, I know I could just do a loop and delete each one explicitly,
but I was kind of wanting to save a little space :)

Anyway, I'm getting an "unresolved external symbol" error ... and
rightly so. Just telling for_each() to CALL this template function
doesn't actually instantiate it. I've found that to use this function
as a functor, I have to do something like this first [for every
type that I want to use checked_delete with]:

checked_delete<SomeType>(0);

This will instantiate the proper function and everything works
great [albeit with one additional line of code].

So, my question: is there a better way to achieve my goal of using
a template function as a function argument to for_each()?
Here's basically what my for_each line is:

for_each(container.begin(), container.end(), boost::checked_delete<SomeType>);


If you're not familiar with boost, checked_delete is a "safer"
delete. The only reason I'm using it is that it won't really cost me
anything ... and it's an existing function that'll delete for me so
I don't need to write my own....

Thank you for your time.

--Paul

Gabriel Fleseriu
February 26th, 2003, 08:35 AM
Make a functor out of it

template <typename T>
class checked_delete
{
public:
void operator(T *t){boost::checked_delete<T>(t);}
};
//.....
for_each(container.begin(), container.end(), checked_delete<SomeType>() );


//note -- I didn't compile this code :)

PaulWendt
February 26th, 2003, 10:33 AM
Thank you for the input. I definitely did consider that approach,
but I would just use delete for it :) I was hoping to reuse boost's
current function so that I wouldn't have to make ANY functor
myself; I was hoping that there would be a ... easier way than
creating a separate functor for it. I never bothered saying that,
of course, so how would anyone know? :)

Unless someone knows something better, I probably WILL use
your approach; actually I already have a Deleter functor ... but I
was hoping to use some existing code so that I could throw
Deleter away :)

Thanks again for your time.

--Paul

galathaea
February 26th, 2003, 03:03 PM
I haven't had any instantiation problem with parametrized functions before, so I tossed together this quick little program.

#include <iostream>
using std::cout;

template <typename SomeType>
void Function(SomeType someInstance)
{
cout << "In the parametrized function!\n";
}

template <typename SomeType>
class SomeClass
{
SomeType member_;
public:
SomeClass(SomeType someInstance) : member_(someInstance)
{
}

void SomeMethod(void (*functionPointer)(SomeType))
{
cout << "In the calling method!\n";
functionPointer(member_);
}
};

int main()
{
SomeClass<int> intClass(666);
intClass.SomeMethod(Function<int>);

return 0;
}

It compiles and runs as expected on MSVC++ 6.0 (sp5), so I'm curious what the problem here is.... I don't need to put the Function<int> anywhere else to instantiate it properly, and I think this simulates the same logic. Have I done anything weirdly different than the original problem here?

PaulWendt
February 26th, 2003, 04:09 PM
Thank you, galathea. I always give people advice by telling them
to create a "stub" program so that others can work with it; I
neglected to do that on my own. However, we're doing slightly
different things.

I removed SomeClass; try this code:


template <typename SomeType>
void Function(SomeType someInstance)
{
cout << "In the parametrized function!\n";
}

int main()
{
//SomeClass<int> intClass(666);
//intClass.SomeMethod(Function<int> );

vector<int> classes;
for_each(classes.begin(), classes.end(), Function<int>);

return 0;
}


My compiler is Visual Studio .NET and I'm getting:

tester error LNK2019: unresolved external symbol "void __cdecl
Function(int)" (?Function@@YAXH@Z) referenced in function _main


I'm going to go try it on Visual Studio 6.0 SP5 and see if I get
the same results. I think I'm going to wind up going the functor
route :P

--Paul

Edit: Oh, it should be noted that if I put the following line in my
program, the function is instantiated and everything works fine.
Could it be that my implementation of for_each is messed up?
I will also go try this on gcc.

Function<int>(0);

PaulWendt
February 26th, 2003, 04:18 PM
Alright, well the code doesn't work with Visual Studio 6.0 either.
I tried it on gcc, however, and everything worked fine there.
I'm assuming, then, that it's a problem with Microsoft's compiler
but I'm going to try e-mailing the comeau compiler to see what
they come up with [I only have the two aforementioned
compilers]

I really should have tried this on gcc first, though. It's so good
with everything else that I just [mistakenly] assume that it's my
code that's wrong and not the compiler while working with
Visual Studio C++ 7.0 :)

--Paul

Graham
February 26th, 2003, 04:32 PM
It's possible that 6.0 is wrong and 7.0 is correct - I wouldn't like to say for sure. Have you tried galathea's example on VC++ 7.0? I can point to a difference between the two, though: in your example, the templated function that's passed as an argument is typed through a template parameter of for_each, whereas in galathea's example the function argument is not further "templatised". This may or may not be relevant (it could be utter twaddle on my part), but I just thought I'd mention it.

galathaea
February 26th, 2003, 04:51 PM
You are absolutely right, Graham, that the two things aren't the same logic. I didn't catch that difference before, so I wrote up

#include <iostream>
using std::cout;

template <typename SomeType>
void Function(SomeType someInstance)
{
cout << "In the parametrized function!\n";
}

template <typename SomeType>
class SomeClass
{
SomeType member_;
public:
SomeClass(SomeType someInstance) : member_(someInstance)
{
}

void SomeMethod(void (*functionPointer)(SomeType))
{
cout << "In the calling method!\n";
functionPointer(member_);
}
};

template <typename SomeType, class Functor>
void CallerFunction (SomeType someInstance, Functor someFunctor)
{
cout << "In the calling function!\n";
someFunctor(someInstance);
}

int main()
{
// method of parametrized class
SomeClass<int> intClass(666);
intClass.SomeMethod(Function<int>);

// parametrized function call
CallerFunction(666, Function<int>);

return 0;
}

and it also compiled and ran as expected!?! I was curious because when I realized the difference, I thought that might be the cause. Now, however, I am stumped and can only expect it to be some inability with the compiler and the for_each specification, but I don't see anything too off with the for_each definition that would cause it...

PaulWendt
February 26th, 2003, 04:52 PM
Originally posted by Graham
It's possible that 6.0 is wrong and 7.0 is correct - I wouldn't like to say for sure. Have you tried galathea's example on VC++ 7.0? I can point to a difference between the two, though: in your example, the templated function that's passed as an argument is typed through a template parameter of for_each, whereas in galathea's example the function argument is not further "templatised". This may or may not be relevant (it could be utter twaddle on my part), but I just thought I'd mention it.

Thanks a lot for your reply. I had some incremental posts along
the way, but as it turns out, the code works on neither Visual
Studio 6.0 nor Visual Studio 7.0. The code DOES compile and
link properly on gcc-3.1. I went to try Comeau's compiler on the
web, only to find out that they do no linking :)

So, my bet is that it's a Visual Studio problem ... but I have a
workaround for now. I will investigate the differences between
galathea's code and my code more strictly, however; thank you
for pointing out the differences.

--Paul

PaulWendt
February 26th, 2003, 04:54 PM
Originally posted by galathaea
Now, however, I am stumped and can only expect it to be some inability with the compiler and the for_each specification, but I don't see anything too off with the for_each definition that would cause it...

I didn't try this, but I might look at STLPort and see if their
for_each has this same problem? It's just a thought. Thank you
all for your wonderful and helpful replies :)

--Paul

Derek_Burdick
August 25th, 2003, 04:51 PM
The code links in 2003. I remember reading that MS fixed a lot of template issues in this release. It may be worth upgrading if you use a lot of templates.

Derek

mwilliamson
August 25th, 2003, 05:26 PM
It appears to be a template bug, since this code compiles and links:

void(* pFn)(int) = Function<int>;
std::for_each( classes.begin(), classes.end(), pFn );

Yves M
August 25th, 2003, 06:07 PM
Originally posted by Derek_Burdick
The code links in 2003. I remember reading that MS fixed a lot of template issues in this release. It may be worth upgrading if you use a lot of templates.

Derek
Yes, confirmed, it works fine in 2003.

It could also be a problem with the for_each implementation in Dinkumware's STL, but I don't see exactly what could be happening.

I'll try it tomorrow with STLPort.

[Edit: doesn't work with STLPort on VC6 either. So it must be a compiler bug.]

mwilliamson
August 25th, 2003, 06:35 PM
I think it is because the compiler doesn't know it is a function pointer? For example, it foreach was defined as:

template<class fIt, class T, class U>
void foreach( fIt beg, fIt end, T (* fn)(U& u) );

i bet it would work.

Yves M
August 25th, 2003, 06:49 PM
That would mean that the unary function needs to have exactly that calling convention and e.g. a function not taking a reference would not qualify for foreach.

fleming
December 15th, 2003, 10:25 PM
BTW, Boost has a checked_deleter functor.