Template problems

T

Tim Frink

Hi,

I want to use a callback function together with
templates. Let's say I've this code:

File a.h:

class A
{
private:
template< typename T >
void func( bool( T::*f)(void) );
};
-----------------

File a.cc:

template< typename T >
void A::func( bool( T::*f)(void) )
{
f();
}
------------------

and another class B that uses "func":

File b.cc:
#include "a.h"

bool B::func2(void)
{
return true;
}

void B::func3()
{
A a;
a->func( &B::func2 );
}

During compilation I get the error
undefined reference to `void A::func<B>(bool (B::*)())'.

The problems seem to be that during compilation of class B, the
template function A::func is not completely known (just the
function declaration of the header file, but not the function
definition). I assume that one solution is to move the function
body of A::func into the header file a.h to make it visible during
compilation of class B.

However, this seems not to be the best solution because I must
reveal the implementation of A::func to anyone who wants to use
it. Without templates, I could compile class A into a library
and just provide the header file a.h together with the library.
So, the users would not see the implementation of class A.
However, when I move code from the source file into the header
file, I show my implementation which I would like to avoid.
Are there any solutions for that? Or are templates in general
crucial when source code must be kept closed?

Best regards,
Tim
 
S

sk_usenet

[snip]
During compilation I get the error
undefined reference to `void A::func<B>(bool (B::*)())'.

The problems seem to be that during compilation of class B, the
template function A::func is not completely known (just the
function declaration of the header file, but not the function
definition). I assume that one solution is to move the function
body of A::func into the header file a.h to make it visible during
compilation of class B.

However, this seems not to be the best solution because I must
reveal the implementation of A::func to anyone who wants to use
it. Without templates, I could compile class A into a library
and just provide the header file a.h together with the library.
So, the users would not see the implementation of class A.
However, when I move code from the source file into the header
file, I show my implementation which I would like to avoid.
Are there any solutions for that? Or are templates in general
crucial when source code must be kept closed?

Check this FAQ --
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14
 
P

Puppet_Sock

Hi,

I want to use a callback function together with
templates. Let's say I've this code:

File a.h:

class A
{
   private:
     template< typename T >
     void func( bool( T::*f)(void) );};
[snips]

Do you really want that private? That seems wrong for a callback.

Also, do you really want it to be a template member function?
Or do you want the class to be a template class? That is, do
you want all the items, of various different types, that make
use of this callback to use the same class A? It would appear
you are trying to collect callbacks for more than one T in the
same instance. Is that really what you want?
Socks
 
S

Stephan Ceram

I wonder, why all those questions? Did it have anything to do
with the problem the OP experienced? Generally speaking, the
link error (this is what the OP's got, isn't it?) is because it
is a function template that is used in 'main' and its source is
not visible so that the compiler can generate the function. But
the design has really nothing to do with it, does it? Simply
tell the OP to place the definition in the header.

That's my point. But when I place the definition into the header
which I want to make visible to other users as API to my library,
also the definition of A::func becomes visible to everyone. And
this is what I would like to avoid. This was the reason of my post
to ask you if there are any solution to not change the semantics
of my code example but still somehow keep the definition of A::func
hidden.

Regards,
 
J

Joe Greer

"How do I make it visible to the client's compiler but not to the
clients themselves?" Well, use a compiler that supports template
export and tell the clients to do the same. If you can, that is.
If you cannot, you're SOL.

V

One other possibility (of limited scope) is to explicitly instantiate your
template with the common types you are likely to want and compile that into
a lib and only ship a forward declaration style template definition in your
header. That won't work if you are shipping a template that is supposed to
work with a user defined class though.

joe
 
T

Tim Frink

Hi,
One other possibility (of limited scope) is to explicitly instantiate your
template with the common types you are likely to want and compile that into
a lib and only ship a forward declaration style template definition in your
header. That won't work if you are shipping a template that is supposed to
work with a user defined class though.

What you mean is probably the second suggested solution in
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.15
(add template class Foo<int>; in Foo.cpp), right?

This example is describing a template class, however I'm using
a template function

template< typename T >
void func( bool( T::*f)(void) );

Can this trick with the forward declaration be also applied to template
functions? If so, what do I have to insert in my example file a.cc?
template class A<B>; won't work.

This solution seems to be a sort of a hack because I must know in
advance what template types will be use for 'T'. Can I add different
forward declarations (obviously this must be adjusted to my template
functions) like
template class A<B>;
template class A<C>;

If so it is still better than using the concrete type of class
for "T".
 
J

Joe Greer

Hi,


What you mean is probably the second suggested solution in
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.15
(add template class Foo<int>; in Foo.cpp), right?

This example is describing a template class, however I'm using
a template function

template< typename T >
void func( bool( T::*f)(void) );

Can this trick with the forward declaration be also applied to
template functions? If so, what do I have to insert in my example file
a.cc? template class A<B>; won't work.

I believe so. The following seems to work for me (I make no guarantees
about it being what you want to do and things like include guards and
doing something useful is left as an exercise), however:

::: t-f.h ::: The public file

template<class T>
bool func(bool (T::*f)(), T * p);


class AlwaysFails
{
public:
bool f();
};

class AlwaysWorks
{
public:
bool f();
};


::: t1.cpp ::: The private implementation distributed as .o or .obj
#include "t-f.h"

bool AlwaysFails::f()
{
return false;
}

bool AlwaysWorks::f()
{
return true;
}

template<class T> bool func( bool (T::*f)(), T * p)
{
return (p->*f)();
}

template bool func( bool (AlwaysFails::*f)(), AlwaysFails * p);



template bool func( bool (AlwaysWorks::*f)(), AlwaysWorks * p);


::: t.cpp ::: The client app
#include <iostream>
#include <ostream>

#include "t-f.h"
int main()
{
AlwaysFails af;
AlwaysWorks aw;

std::cout << "AlwaysFail = " << func(&AlwaysFails::f, &af) <<
std::endl;

std::cout << "AlwaysWork = " << func(&AlwaysWorks::f, &aw) <<
std::endl;

}


This solution seems to be a sort of a hack because I must know in
advance what template types will be use for 'T'. Can I add different
forward declarations (obviously this must be adjusted to my template
functions) like
template class A<B>;
template class A<C>;

If so it is still better than using the concrete type of class
for "T".

Yes, its definitely a work-around. You really want an idealized form of
export. Idealized in the sense that it couldn't be reverse engineered.
(Even with export, the source needs to be destributed, but it's in some
internal form, An ambitious soul could decompile it into the original
source, so its still a less than ideal solution, but compilers aren't
really into the security business so AFAIK the export files aren't that
hard to reverse).

HTH,
joe
 

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,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top