Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Template instantiation with gcc

Status
Not open for further replies.

aveek

Programmer
Jan 18, 2003
2
US
I have a shared library which contains the definition of a template class. I am instantiating the template class in a main file and compiling with gcc but it is giving me a lot of problems. It seems that the gcc compiler does not have visibility to template definitions if the template definition and instantiation are done at different places. Now I know that one way to solve this problem is to pull out the definitions and put it in the translation unit where it is actually getting instantiated but that is simply not feasible in my application as it implies that I have to do #include of the cpp file where the definition resides at hundreds of places inside my code. Another option would be to place my template definition within my header files which are anyway included at places where the template is being instantiated. But there is a problem with this solution too. We have a SDK that we make available to the end customer and this SDK includes the header files. So if we were to put the template defintions in the header files we would be exposing our code which is not what we want. I have tried all the template related options of the g++ compiler such as -fno-implicit-templates, -fexternal-templates and -falt-external-templates but to no avail.

Can someone please lead me to a simple and elegant solution?
 
Can you put explicit instantiations anywhere? Perhaps in a header that all involved files #include?

e.g.

Code:
  template<>
class MyTemplateClass<int>;
  template<>
class MyTemplateClass<double>;
  template<>
class MyTemplateClass<MyClass>;
  template<>
class MyTemplateClass<MyTemplateClass<int> >;
 
That would mean I would have to put all the possible permutations of the template class instantiation in a header file and include it. I have got about 20 template classes with prototypes like

template class MyTemplateClass<class T1, class T2, class T3>

If I were to work out all the possible combinations of the data types that the template class can be instantianted with, it becomes really cumbersome and when I consider the fact that there are 20 such template classes, I have a mind boggling number of instantiations to be made.
 
g++ will try to compile the .cpp files, all templates should be .template files. The class in the .h must have a templated declaration and each function in the .template must have the template prefix. When in doubt write it using a type def and an int and then switch to your template. Enjoy.
 
As far as I know, there's no way to keep from exposing your code aside from using explicit instantiations. Perhaps you could write an external program to generate all the permutations? Or maybe you could do some macro hacking? Not the best way in the world of doing things, but...

Note that not even the semi-mythical export keyword, which is meant to allow separate compilation of templates, keeps you from exposing your code. The only way to accomplish that is to actually have the template classes individually compiled, and the only way to do that (that I know of) is to give the explicit instantiations.
 
Why not expose your code? It may be a good idea to leave the source open, even if you do copyright the product... This way, you get the money for selling it, people know whats going on in it, and can change their copy of the code... but to copy and distrbute it would be illegal without your permission.
 
There are ways to work around this.

However, consider the following questions

1) If you don't share a definition of the template no one else is going to be able compile custom versions of the template (it doesn't have to be this way, but it is as templates never really got past the glorified macro stage). If you think you can get away with a pseudo definition in a .o or .so file somewhere, what format do you think will be used to ensure cross platform portability. Sounds like a parse tree or even vanilla source to me. Easily reverse engineerable in either case by poking on the appropriate file.

2) Why can't you ensure the same protection for your code through NDA, copyright, patent, licensing, etc?

Ok, given that you _want_ to protect your code from exposure in near source form, here's how to do it.

Remember back in the days of C when the first argument to every function in an ADT was a pointer to the representation for that ADT? Well you can do the same thing in C++, but one better.

1) Redefine your code to take classes rather than be constructed with templates
2) Create templates (in a .h) that transform any type into the classes your code likes (and back again without casting on the user end).

You're Done!

I'm going to post a couple more times with different source to show how it's done.

 
/* here's the main code that I used unchanged for both of the following code structures */

#include <iostream>
#include <string>

/* I changed this line to a different header but no other changes to this file */
#include &quot;sample3.hh&quot;

class myImpl : public std::string
{
public:
std::string data() const
{
return (*this);
}
};

int main(void)
{
Logger<myImpl> logger;


myImpl name;

std::cout << &quot;Enter a name.&quot; << std::endl;
std::cin >> name;

logger.log(name);

return 0;
}
 
/*
* This is the normal way of doing things, all in a header.
* Even if YOU can get around it, your clients can't if they
* use gcc
*/

#include <iostream>
#include <string>

template< class SomeT > class Logger
{
public:
bool log(const SomeT& a_problem);
};

template< class SomeT > bool Logger< SomeT >::log(const SomeT& a_problem)
{
std::cout << a_problem.data() << std::endl;

return true;
}
 
/* this is the way that hides your code. the namespace
* SecretLogger can be defined in any linked file. Wrapped
* also acts like a constraint on the Logger template as
* only the functions declared there are available in your
* hidden code
*/

#include <iostream>
#include <string>

class Wrapped
{
public:
virtual std::string data(void) const = 0;
};

namespace SecretLogger
{
bool log (const Wrapped& a_problem);
}

/*
* inherit the impl from SomeT and the interface of Wrapped
*/
template< class SomeT > class Wrapper : public SomeT, public virtual Wrapped
{
public:
Wrapper (const SomeT& a_arg) : SomeT(a_arg) {}
std::string data(void) const { return SomeT::data(); }
};

template < class SomeT > class Logger
{
public:
bool log(const SomeT& a_problem)
{
return SecretLogger::log(Wrapper< SomeT >(a_problem));
}
};

/* put this wherever your heart desires, must still be
* linked though
*/
namespace SecretLogger
{
bool log (const Wrapped& a_problem)
{
std::cout << a_problem.data() << std::endl;
}
}
 
There are some caveats though. You have to wrap all types that go into/out of your secret code. If you have a need to construct values of user based types (template arguments), you'll need to add hooks for delegated instantiation. You'll likely run into the fact that gcc loves to give errors like
=============
sample2.hh:26: sorry, not implemented: adjusting pointers for covariant returns
=============
if you try to use covarient references, it'll be happy with pointers though.

Since I can do this manually, wouldn't it be nice if the compiler did it automatically? Sorry. No luck, templates get instantiated multiple times rather than multiple instantiations of wrapper classes. Try functors in say ML or other more advanced languages if you don't like the extra work you need to do each time.

ahhh the fun of an advanced language feature (templates) that evolved out of a low level one (macros).
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top