g++ templates instatiation libraries

I am using gcc 4.6 on fedora.

I have not been able to create an external library,
composed of template function instantiations, that
will link with the rest of the code.

Using nm -CBgo, I see that the following are the
types of symbols that link properly:

T GEN_IoCopy(std::istream&, int&)

Such symbols are required by the rest of the program,
and are supplied by normal libraries (not template libraries).

However, when using explicit template instantiation to
form the library, the
external template library provides symbols of the form

W bool GEN_IoCopy<int>(std::istream&, int&)

Note the "W", indicating "Weak", and the <int> indicating
that it is from a template. So, the linker is not happy.

How do we sync external template libraries with the
rest of the code in a program? I have tried all types of
forward declarations for the template symbols, to no avail.

Thank you.
Template libraries are in the headers, not in object code. Take a look at boost!
I wish to build my own template libraries, and not having all the code in the headers.
Boost has many header-only template libraries, but it does not need to be that way.
By knowing how to do both approaches, the developer can make an informed choice
for each unique situation.
Boost has many header-only template libraries, but it does not need to be that way.


Actually, on pretty much all compilers it must be done that way since no-one supports export.
My apologies on this. I got this working. Don't know what I was doing wrong, before.
You can compile/link the following two source files with -std=c++0x,
and the program will correctly print out, "9".

1
2
3
4
5
6
7
template< class T >
T f( T t )
{
  return t*t;
}

template int f( int );


and

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

template< class T >
T f( T t );

extern template int f( int );

int main( void )
{
  const int b = f( 3 );
  
  cout << b << endl;
  return 0;
}
closed account (1yR4jE8b)
Don't know what I was doing wrong, before.


The compiler doesn't generate code for templates until it is required to, because you are creating an explicit specialization for it template int f( int );, you get the relevant function to be generated.
Although the explicit templates are working for me, there is a question
about this that bothers me:

Why do we need a special template function forward declaration?
1
2
3
4
template< class T >
T f( T t );

extern template int f( int );

Instead of the above four lines of code,
why not just the standard single-line, non-template, function forward declaration:
 
int f( int );

After all, the symbol generated by the template mechanism has the same signature, and,
I assume, the same argument passing semantics as a symbol generated by
a non-template function definition. What does it matter whether or not
it was generated by a template mechanism?

This is more than an aesthetics issue. Having the template forward declaration
1
2
template< class T >
T f( T t );

introduces the chance of ambiguous/extraneous template matching. I have had to mildly
re-juggle my code and convert some template instantiation to less elegant non-template
instantiation.

why not just the standard single-line, non-template, function forward declaration:


Because for the template version you need to actually generate the function. For the non-template version the function is already defined somewhere.
In the situation I described, the template instance is already defined, and has been created in
another translation unit -- the forward declaration has no effect on that.
Then you wouldn't be able to forward declare another function called f that is a non-template function that has the same parameters/return type.
You are right! I did a test, and was able to use the template
f by calling f<>(3) (it seems that the regular f takes precedence
over the template f).

My objection is to needing to have the following as part of the
forward declaration:

1
2
3
// Template declaration
template< class T >
T f( T t );

It causes the compiler to match stuff that I don't want matched. Whereas,
if the forward declaration were only

1
2
  // Extern template function declaration
extern template int f( int );

then we could have the best of both worlds.
Why is the Extern template function declaration not enough?
Why do we also need to have the Template declaration?
Is it because template parameters are matched differently from regular
parameters, when resolving overloaded functions?



I thought I would share a solution that I just worked out, a way
to forward declare template functions without having a forward
template declaration. This solves the problem I described in my
previous submission. The following two source files are an example.

1
2
3
4
5
6
7
8
9
10
11
// Define and instantiate a template function
template< class T >
T f( T t )
{
  return t*t;
}
template int f( int );

// Point a regular function to the template function
typedef int FF( int );
FF* g = f;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

typedef int FF( int );
extern FF* g;
FF* f = g;

int main( void )
{
  const int b = f( 3 );
  
  cout << b << endl;
  return 0;
}


The above two source files compile and link, and runs to output the value, "9".
So, the template function f is in a template library, and is (indirectly) forward
declared without any template declarations.
Last edited on
I don't think that's any better than forward declaring it. You still need to know the types of the arguments to make the function pointer.

Why is the Extern template function declaration not enough?
Why do we also need to have the Template declaration?
Is it because template parameters are matched differently from regular
parameters, when resolving overloaded functions?


It's because you could have several different template functions:

1
2
template <class T> T f(T); //...
template <class U, class T> U f(T); //... 


How would the compiler know which one you were trying to forward declare?
Thank you for clarifying the reason for the Template declaration.

I don't think the example you gave is valid, however, since overloading by
return value is not allowed.

Nonetheless, your question is a good one. The programmer has full control over
which functions get used. When forming a template library, you know which types
are being used to instantiate the templates, and you can choose different names
for the various functions, for what the main function sees, when using the scheme that
I outlined, above.

Explicitly, the line
FF* f = g;
can be omitted from my last example, and the main functions can then still use
the name, 'g', for the original template function, 'f'.

I would be very interested to see a situation where a template library is limited in any way by exposing it in the way that I have described.
I don't think the example you gave is valid, however, since overloading by
return value is not allowed.


Yeah, you're right. It would always be ambiguous.

Explicitly, the line
FF* f = g;
can be omitted from my last example, and the main functions can then still use
the name, 'g', for the original template function, 'f'.


I just tried:

main:
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;

int main( void )
{
  const int b = f( 3 );
  
  cout << b << endl;
  return 0;
}


other.cpp
1
2
3
4
5
6
7
// Define and instantiate a template function
template< class T >
T f( T t )
{
  return t*t;
}
template int f( int );


and got:
Error 1 error C3861: 'f': identifier not found c:\users\firedraco\documents\visual studio 2008\projects\sandbox\sandbox\main.cpp 6
You need to forward declare 'f' before the main() function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

template< class T >
T f( T t );
extern template int f( int );

int main( void )
{
  const int b = f( 3 );
  
  cout << b << endl;
  return 0;
}

or use the non-template-type forward declaration that I described in an earlier post.
Topic archived. No new replies allowed.