header file for template functions/classes

J

Jess

Hello,

I was told that if I have a template class or template function, then
the definitions must be put into the header file where I put the
declarations. On the other hand, it is generally good to put source
code and declaration into separate files (.h head filer and .cpp
source file). What can I do to template functions/classes? Do I have
to put them all into one header file?

Thanks,
Jess
 
B

Bo Persson

Jess wrote:
:: Hello,
::
:: I was told that if I have a template class or template function,
:: then the definitions must be put into the header file where I put
:: the declarations. On the other hand, it is generally good to put
:: source code and declaration into separate files (.h head filer and
:: .cpp source file). What can I do to template functions/classes?
:: Do I have to put them all into one header file?
::

In theory - no. In practice - Yes.

There is a keyword 'export' in C++, that lets's you write 'export
template...' in the header and then store the implementation in a .cpp
file.

Unfortunately, it is very hard to find a compiler that actually
implements this. :-(



Bo Persson
 
J

Juha Nieminen

Bo said:
There is a keyword 'export' in C++, that lets's you write 'export
template...' in the header and then store the implementation in a .cpp
file.

Unfortunately, it is very hard to find a compiler that actually
implements this. :-(

If I understand correctly, the reason why there are still basically
no compilers which support this is because C/C++ compilers have been
for decades designed as a two-part system: The compiler, which creates
object files, and the linker which creates the final executable from
the object files (and possibly libraries). The linker is often very
independent from the compiler and only understands object files.
This makes sense because it allows object files to be created with
different compilers and even different languages, and then they can
be linked together to form one executable. It's not even uncommon
that some precompiled libraries have been created with a completely
different compiler than the one you are using to compile your program.

The difficulty with export templates is that they require the linker
to call the C++ compiler at linking stage. This, of course, creates
heavy dependencies between the linker and the C++ compiler and presents
all kinds of problems which compiler developers seemingly are unwilling
to tackle with at least for now.
 
J

James Kanze

If I understand correctly, the reason why there are still basically
no compilers which support this is because C/C++ compilers have been
for decades designed as a two-part system: The compiler, which creates
object files, and the linker which creates the final executable from
the object files (and possibly libraries). The linker is often very
independent from the compiler and only understands object files.

That may have been true 20 years ago, but I don't think it's
true for any modern C++ compiler. For that matter, even CFront
used a pre-linker (or was it a post-linker), and link time
instantiation of templates. Today, of course, any compiler
worth its salt does intermodule optimization---at link time,
using output from the profiler.
This makes sense because it allows object files to be created with
different compilers and even different languages, and then they can
be linked together to form one executable. It's not even uncommon
that some precompiled libraries have been created with a completely
different compiler than the one you are using to compile your program.
The difficulty with export templates is that they require the linker
to call the C++ compiler at linking stage.

Not necessarily. They do require that information from the
source files with the exported templates be available when the
template is instantiated. How the compiler does this is up to
it.
This, of course, creates heavy dependencies between the linker
and the C++ compiler and presents all kinds of problems which
compiler developers seemingly are unwilling to tackle with at
least for now.

Which is why the one vendor which does fully support export only
sells front-ends, and doesn't require any additional linker
support for it at all?

Since it's earliest days, C++ has required more than the
classical linker provided, and has used various pre- or
post-linker solutions, or linker wrappers, to provide the
additional features. Export doesn't create any additional
problems in that regard.
 
M

Marcus Kwok

Bo Persson said:
Jess wrote:
:: Hello,
::
:: I was told that if I have a template class or template function,
:: then the definitions must be put into the header file where I put
:: the declarations. On the other hand, it is generally good to put
:: source code and declaration into separate files (.h head filer and
:: .cpp source file). What can I do to template functions/classes?
:: Do I have to put them all into one header file?
::

In theory - no. In practice - Yes.

There is a keyword 'export' in C++, that lets's you write 'export
template...' in the header and then store the implementation in a .cpp
file.

Unfortunately, it is very hard to find a compiler that actually
implements this. :-(

True... I think Comeau is the only compiler that officially supports it,
but I think I heard that the Intel compiler has an undocumented switch
for it.

However, the FAQ has a workaround to simulate the export keyword (only
so far as to let you put the definitions in a different file than the
declarations):
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14
 
J

Jess

That may have been true 20 years ago, but I don't think it's
true for any modern C++ compiler. For that matter, even CFront
used a pre-linker (or was it a post-linker), and link time
instantiation of templates. Today, of course, any compiler
worth its salt does intermodule optimization---at link time,
using output from the profiler.


Not necessarily. They do require that information from the
source files with the exported templates be available when the
template is instantiated. How the compiler does this is up to
it.


Which is why the one vendor which does fully support export only
sells front-ends, and doesn't require any additional linker
support for it at all?

Since it's earliest days, C++ has required more than the
classical linker provided, and has used various pre- or
post-linker solutions, or linker wrappers, to provide the
additional features. Export doesn't create any additional
problems in that regard.

--
James Kanze (Gabi Software) email: (e-mail address removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


I tried to put the declarations in a .h file, with "export" keyword.
When I compiled the code, my compiler said "export" wasn't implemented
and would be ignored. However, the .h file plus the separate .cpp file
actually worked together. If the compiler doesn't implement "export",
how could all these work out?

Jess
 
J

John Harrison

I tried to put the declarations in a .h file, with "export" keyword.
When I compiled the code, my compiler said "export" wasn't implemented
and would be ignored. However, the .h file plus the separate .cpp file
actually worked together. If the compiler doesn't implement "export",
how could all these work out?

Jess

Without seeing your code who can say? Maybe you are doing explicit
instantiation (or whatever it's called).

john
 
J

Jess

Without seeing your code who can say? Maybe you are doing explicit
instantiation (or whatever it's called).

john


The header file is (test.h):

export template<class T> class A{
public:
void f() const;
A(T a):x(a){}
private:
T x;
};

The source code is:

#include<iostream>
#include "test.h"

using namespace std;

template<class T>
void A<T>::f() const{
cout << x << endl;
};


int main(){
A<int> a(10);
a.f();
return 0;
}

Jess
 
B

Bo Persson

Jess wrote:
:: On May 19, 8:50 pm, John Harrison <[email protected]>
:: wrote:
:::: I tried to put the declarations in a .h file, with "export"
:::: keyword. When I compiled the code, my compiler said "export"
:::: wasn't implemented and would be ignored. However, the .h file
:::: plus the separate .cpp file actually worked together. If the
:::: compiler doesn't implement "export", how could all these work
:::: out?
:::
:::: Jess
:::
::: Without seeing your code who can say? Maybe you are doing explicit
::: instantiation (or whatever it's called).
:::
::: john
::
::
:: The header file is (test.h):
::
:: export template<class T> class A{
:: public:
:: void f() const;
:: A(T a):x(a){}
:: private:
:: T x;
:: };
::
:: The source code is:
::
:: #include<iostream>
:: #include "test.h"
::
:: using namespace std;
::
:: template<class T>
:: void A<T>::f() const{
:: cout << x << endl;
:: };
::
::
:: int main(){
:: A<int> a(10);
:: a.f();
:: return 0;
:: }
::

This works because the implementation of f() is present in the same
file as its use. The effect is the same as if it was put in the header
file.

The including of files is performed by the preprocessor, long before
the compiler starts to look at the code. When you reach that stage, it
appears as one large file with all includes and preprocessor macros
already resolved.

If you were to put f() in a separate A.cpp file, the compiler would
not find it (when ignoring the export keyword).


Bo Persson
 
J

Jess

Jess wrote:


:::: I tried to put the declarations in a .h file, with "export"
:::: keyword. When I compiled the code, my compiler said "export"
:::: wasn't implemented and would be ignored. However, the .h file
:::: plus the separate .cpp file actually worked together. If the
:::: compiler doesn't implement "export", how could all these work
:::: out?
:::
:::: Jess
:::
::: Without seeing your code who can say? Maybe you are doing explicit
::: instantiation (or whatever it's called).
:::
::: john
::
::
:: The header file is (test.h):
::
:: export template<class T> class A{
:: public:
:: void f() const;
:: A(T a):x(a){}
:: private:
:: T x;
:: };
::
:: The source code is:
::
:: #include<iostream>
:: #include "test.h"
::
:: using namespace std;
::
:: template<class T>
:: void A<T>::f() const{
:: cout << x << endl;
:: };
::
::
:: int main(){
:: A<int> a(10);
:: a.f();
:: return 0;
:: }
::

This works because the implementation of f() is present in the same
file as its use. The effect is the same as if it was put in the header
file.

The including of files is performed by the preprocessor, long before
the compiler starts to look at the code. When you reach that stage, it
appears as one large file with all includes and preprocessor macros
already resolved.

If you were to put f() in a separate A.cpp file, the compiler would
not find it (when ignoring the export keyword).

Bo Persson

I see, thanks a lot. In addition, if I run the program on a compiler
that supports export, shall I export the implemenations (in .cpp) or
the declarations (in .h)? Shall I export each individual functions
like

export template<class T> A<T>::f()...
export template<class T> A<T>::g()..

or make one "export" declaration at the top of the file?

I remember there's another keyword "extern", which indicates the
current declaration isn't a definition and it implies the definition
is at somewhere else. This sounds similar to "export", what's the
difference between them?

Thanks,
Jess
 
J

James Kanze

On May 18, 8:24 am, James Kanze <[email protected]> wrote:

[...]
I tried to put the declarations in a .h file, with "export" keyword.
When I compiled the code, my compiler said "export" wasn't implemented
and would be ignored. However, the .h file plus the separate .cpp file
actually worked together. If the compiler doesn't implement "export",
how could all these work out?

Many vendors are too lazy to implement export, and don't really
care about their users. There are exceptions. The discussion
wasn't about what current compilers do, it was about why.
Someone purported technical reasons why a compiler wouldn't
implement export; all I'm doing is pointing out that they don't
exist.
 
J

Jess

Since my compiler doesn't support "export", I'm trying to put .h
and .cpp into two files and then "include" one into the other. I
tried to include the source file (src.cpp) in my header file
(header.h) by putting

#include "src.cpp"

into "header.h" (near the end of the header file).

The problem with this method is that I can't separately compile the
"src.cpp" file, because all the other "include" headers and the
template declarations are in "header.h". I don't think I can put
another set of "include" in "src.cpp", because it would introduce
multiple declarations.

To me, it seems I'd have to put

#include "header.h"

into src.cpp and remove the

#include "src.cpp"

line from "header.h". However, I'm not sure whether this is possible,
because the compiler needs to see the source code in the header file.
How can I solve this problem?

Thanks,
Jess
 
M

Marcus Kwok

Jess said:
Since my compiler doesn't support "export", I'm trying to put .h
and .cpp into two files and then "include" one into the other. I
tried to include the source file (src.cpp) in my header file
(header.h) by putting

#include "src.cpp"

into "header.h" (near the end of the header file).

The problem with this method is that I can't separately compile the
"src.cpp" file, because all the other "include" headers and the
template declarations are in "header.h". I don't think I can put
another set of "include" in "src.cpp", because it would introduce
multiple declarations.

To me, it seems I'd have to put

#include "header.h"

into src.cpp and remove the

#include "src.cpp"

line from "header.h". However, I'm not sure whether this is possible,
because the compiler needs to see the source code in the header file.
How can I solve this problem?

Make sure you have appropriate include guards in your header files.
Here is a simple working example I created:


// export_template.h
#ifndef EXPORT_TEMPLATE_H
#define EXPORT_TEMPLATE_H

template <typename T>
class Foo {
public:
Foo();
void print() const;
private:
T val_;
};

#ifndef USE_EXPORT_KEYWORD
#include "export_template.cpp"
#endif

#endif


// export_template.cpp
#include "export_template.h"
#include <iostream>

template <typename T>
Foo<T>::Foo() : val_(42) { }

template <typename T>
void Foo<T>::print() const
{
std::cout << "val = " << val_ << '\n';
}


// export_template_use.cpp
#include "export_template.h"
#include <iostream>

int main()
{
Foo<int> f;
f.print();
}


Then just compile export_template_use.cpp. No need to compile
export_template.cpp on its own, since my compiler doesn't support export
either.

Also, the FAQ has a technique so that will allow you to use the export
keyword if your compiler supports it in the future (this has been
integrated into the above example):
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14
 
J

Jess

Make sure you have appropriate include guards in your header files.
Here is a simple working example I created:

// export_template.h
#ifndef EXPORT_TEMPLATE_H
#define EXPORT_TEMPLATE_H

template <typename T>
class Foo {
public:
Foo();
void print() const;
private:
T val_;

};

#ifndef USE_EXPORT_KEYWORD
#include "export_template.cpp"
#endif

#endif

// export_template.cpp
#include "export_template.h"
#include <iostream>

template <typename T>
Foo<T>::Foo() : val_(42) { }

template <typename T>
void Foo<T>::print() const
{
std::cout << "val = " << val_ << '\n';

}

// export_template_use.cpp
#include "export_template.h"
#include <iostream>

int main()
{
Foo<int> f;
f.print();

}

Then just compile export_template_use.cpp. No need to compile
export_template.cpp on its own, since my compiler doesn't support export
either.

Also, the FAQ has a technique so that will allow you to use the export
keyword if your compiler supports it in the future (this has been
integrated into the above example):http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14


Many thanks for your example, that really helps. :) So I see the key
is have the well-defined guards. I think I can remove

#ifndef USE_EXPORT_KEYWORD

if I don't expect to run my program on any compiler supporting
"export" keyword.
Jess
 

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

No members online now.

Forum statistics

Threads
474,294
Messages
2,571,511
Members
48,201
Latest member
JefferyBur

Latest Threads

Top