separating definitions from declarations when using templates

A

aaragon

Hi everyone,

I've been writing some code and so far I have all the code written in
the .h files in order to avoid the linker errors. I'm using templates.
I wanted to move the implementations to the .cpp files. After some
reading, I found that the only way to do this is to add the actual
template instantiations in the .cpp file. But, how do you do that if
you're not working with built-in types? For example, a template class
might be,

template
<
class Objective,
class StoragePolicy,
int kclass ClassA {
....
// declarations and definitions
....
}

How do I separate this into .cpp and .h files if I Objective and
StoragePolicy are defined by the user of the code? In this example,
StoragePolicy is something that I could define (let's say
std::vector), but Objective is an object that the user provides. Is
there a way to get around this? I read also something about using the
"export" keyword but it doesn't seem to work with gnu g++. Any help
will be appreciated.

a^2
 
K

Kai-Uwe Bux

aaragon said:
Hi everyone,

I've been writing some code and so far I have all the code written in
the .h files in order to avoid the linker errors. I'm using templates.
I wanted to move the implementations to the .cpp files. After some
reading, I found that the only way to do this is to add the actual
template instantiations in the .cpp file. But, how do you do that if
you're not working with built-in types? For example, a template class
might be,

template
<
class Objective,
class StoragePolicy,
int k
class ClassA {
...
// declarations and definitions
...
}

How do I separate this into .cpp and .h files if I Objective and
StoragePolicy are defined by the user of the code?

Short answer: you don't.
In this example,
StoragePolicy is something that I could define (let's say
std::vector), but Objective is an object that the user provides. Is
there a way to get around this? I read also something about using the
"export" keyword but it doesn't seem to work with gnu g++.

The export keyword is meant for this purpose, however, most compilers don't
support it.
Any help will be appreciated.

Your options include:

a) leave the implementation code in the header files. This is common
practice.

b) use a compiler that supports "export". This is not common and will render
you code less portable.


Best

Kai-Uwe Bux
 
A

aaragon

Short answer: you don't.


The export keyword is meant for this purpose, however, most compilers don't
support it.


Your options include:

a) leave the implementation code in the header files. This is common
practice.

b) use a compiler that supports "export". This is not common and will render
you code less portable.

Best

Kai-Uwe Bux

Thanks for your reply. I'll go with option a) for now. Best regards.
 
P

paul.joseph.davis

Thanks for your reply. I'll go with option a) for now. Best regards.


aaragon,

Although this isn't removing it from #included headers, this is a good
way to separate the implementation from definition in files.

/////foo.hh

#ifndef FOO_HH
#define FOO_HH

template< typename TYPE >
void
foo( TYPE val ) ;

#include "foo.tcc"

#endif

////foo.tcc

#include <iostream>

template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;
}

////main.cc

#include "foo.hh"

int
main( int argc, char* argv[] )
{
foo( 1 ) ;
}

///End of example.

HTH,

Paul Davis
 
D

Dave Rahardja

Thanks for your reply. I'll go with option a) for now. Best regards.


aaragon,

Although this isn't removing it from #included headers, this is a good
way to separate the implementation from definition in files.

/////foo.hh

#ifndef FOO_HH
#define FOO_HH

template< typename TYPE >
void
foo( TYPE val ) ;

#include "foo.tcc"

#endif

////foo.tcc

#include <iostream>

template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;
}

////main.cc

#include "foo.hh"

int
main( int argc, char* argv[] )
{
foo( 1 ) ;
}

///End of example.

HTH,

Paul Davis

I would even suggest:

// export_support_begin.hh

#if defined(EXPORT)
#undef EXPORT

#if defined(EXPORT_KEYWORD_SUPPORT)
#define EXPORT export
#else
#define EXPORT
#endif


// export_support_end.hh

#undef EXPORT


// foo.hh

#ifndef FOO_HH
#define FOO_HH

#include "export_support_begin.hh"

EXPORT template< typename TYPE >
void
foo( TYPE val ) ;

#if !defined(EXPORT_KEYWORD_SUPPORT)
#include "foo.tcc"
#endif

#include "export_support_end.hh"

#endif


// foo.tcc

#include <iostream>

#include "foo.hh"
#include "export_support_begin.hh"

EXPORT template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;
}

#include "export_support_end.hh"


// main.cc

#include "foo.hh"

int
main( int argc, char* argv[] )
{
foo( 1 ) ;
}


That way you can define EXPORT_KEYWORD_SUPPORT on compilers that support the
export keyword (notably Comeau and other compilers that use the EDG front
end).

It is safe to compile foo.tcc even on a noncompliant compiler.

-dr
 
P

paul.joseph.davis

Although this isn't removing it from #included headers, this is a good
way to separate the implementation from definition in files.

#ifndef FOO_HH
#define FOO_HH
template< typename TYPE >
void
foo( TYPE val ) ;
#include "foo.tcc"


#include <iostream>
template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;
}

#include "foo.hh"
int
main( int argc, char* argv[] )
{
foo( 1 ) ;
}
///End of example.

Paul Davis

I would even suggest:

// export_support_begin.hh

#if defined(EXPORT)
#undef EXPORT

#if defined(EXPORT_KEYWORD_SUPPORT)
#define EXPORT export
#else
#define EXPORT
#endif

// export_support_end.hh

#undef EXPORT

// foo.hh

#ifndef FOO_HH
#define FOO_HH

#include "export_support_begin.hh"

EXPORT template< typename TYPE >
void
foo( TYPE val ) ;

#if !defined(EXPORT_KEYWORD_SUPPORT)
#include "foo.tcc"
#endif

#include "export_support_end.hh"

#endif

// foo.tcc

#include <iostream>

#include "foo.hh"
#include "export_support_begin.hh"

EXPORT template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;

}

#include "export_support_end.hh"

// main.cc

#include "foo.hh"

int
main( int argc, char* argv[] )
{
foo( 1 ) ;

}

That way you can define EXPORT_KEYWORD_SUPPORT on compilers that support the
export keyword (notably Comeau and other compilers that use the EDG front
end).

It is safe to compile foo.tcc even on a noncompliant compiler.

-dr


I dunno. That seems like an awful lot of work for rather little pay
off. I'm not entirely certain about how the export keyword works, but
I imagine all this would save is the redundant compilation of a
multiple templates with the same type parameters.

Paul Davis
 
P

paul.joseph.davis

aaragon wrote:
Hi everyone,
I've been writing some code and so far I have all the code written in
the .h files in order to avoid the linker errors. I'm using templates.
I wanted to move the implementations to the .cpp files. After some
reading, I found that the only way to do this is to add the actual
template instantiations in the .cpp file. But, how do you do that if
you're not working with built-in types? For example, a template class
might be,
template
<
class Objective,
class StoragePolicy,
int k
class ClassA {
...
// declarations and definitions
...
}
How do I separate this into .cpp and .h files if I Objective and
StoragePolicy are defined by the user of the code?
Short answer: you don't.
In this example,
StoragePolicy is something that I could define (let's say
std::vector), but Objective is an object that the user provides. Is
there a way to get around this? I read also something about using the
"export" keyword but it doesn't seem to work with gnu g++.
The export keyword is meant for this purpose, however, most compilers don't
support it.
Any help will be appreciated.
Your options include:
a) leave the implementation code in the header files. This is common
practice.
b) use a compiler that supports "export". This is not common and will render
you code less portable.
Best
Kai-Uwe Bux
Thanks for your reply. I'll go with option a) for now. Best regards.
aaragon,
Although this isn't removing it from #included headers, this is a good
way to separate the implementation from definition in files.
/////foo.hh
#ifndef FOO_HH
#define FOO_HH
template< typename TYPE >
void
foo( TYPE val ) ;
#include "foo.tcc"
#endif
////foo.tcc
#include <iostream>
template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;
}
////main.cc
#include "foo.hh"
int
main( int argc, char* argv[] )
{
foo( 1 ) ;
}
///End of example.
HTH,
Paul Davis
I would even suggest:
// export_support_begin.hh
#if defined(EXPORT)
#undef EXPORT
#if defined(EXPORT_KEYWORD_SUPPORT)
#define EXPORT export
#else
#define EXPORT
#endif
// export_support_end.hh
#undef EXPORT
// foo.hh
#ifndef FOO_HH
#define FOO_HH
#include "export_support_begin.hh"
EXPORT template< typename TYPE >
void
foo( TYPE val ) ;
#if !defined(EXPORT_KEYWORD_SUPPORT)
#include "foo.tcc"
#endif
#include "export_support_end.hh"

// foo.tcc
#include <iostream>
#include "foo.hh"
#include "export_support_begin.hh"
EXPORT template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;

#include "export_support_end.hh"
// main.cc
#include "foo.hh"
int
main( int argc, char* argv[] )
{
foo( 1 ) ;

That way you can define EXPORT_KEYWORD_SUPPORT on compilers that support the
export keyword (notably Comeau and other compilers that use the EDG front
end).
It is safe to compile foo.tcc even on a noncompliant compiler.

I dunno. That seems like an awful lot of work for rather little pay
off. I'm not entirely certain about how the export keyword works, but
I imagine all this would save is the redundant compilation of a
multiple templates with the same type parameters.

Paul Davis

Thought this was an interesting topic I haven't read enough about so I
googled around a bit and found a two articles about export. One for
and one against.

Against:
http://std.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/n1426.pdf

For:
http://www.comeaucomputing.com/iso/promises.html

Personally, I really don't see the motivation for a compiler to
support the feature other than to be fully standards conformant. The
article that was for keeping and requiring export did little to
convince me that export was a Good Thing (TM). In general the argument
seemed to be built on arguments that had little to do with the
theoretical aspects of why export is good and should be kept, instead
focusing on the fact that so much has already been put into it and its
not the only hard feature to implement.

The fact that this feature is so prohibitive to implement that major
compiler vendors aren't supporting it says something to me. I mean,
these people write *compilers* for a living. Although anecdotal and
trivial, how many features have made major compilers balk at
supporting them due to the prohibitively complex nature? I'd imagine
thats a fairly short list.
From what I've seen, all the 'odd' rules (e.g. koenig lookup) that
make up C++ have a very sound theoretical reason behind them. I
haven't found a good reason for supporting export other than the
original topic of separating template implementation from definition.

As always though, if someone can show me an example that will
absolutely not work without export I'd be happy to change my tune.
But until then, it seems like a waste of effort for compiler
developers.

Paul Davis
 
A

aaragon

On 9 Feb 2007 18:04:38 -0800, "(e-mail address removed)"
aaragon wrote:
Hi everyone,
I've been writing some code and so far I have all the code written in
the .h files in order to avoid the linker errors. I'm using templates.
I wanted to move the implementations to the .cpp files. After some
reading, I found that the only way to do this is to add the actual
template instantiations in the .cpp file. But, how do you do that if
you're not working with built-in types? For example, a template class
might be,
template
<
class Objective,
class StoragePolicy,
int k
class ClassA {
...
// declarations and definitions
...
}
How do I separate this into .cpp and .h files if I Objective and
StoragePolicy are defined by the user of the code?
Short answer: you don't.
In this example,
StoragePolicy is something that I could define (let's say
std::vector), but Objective is an object that the user provides. Is
there a way to get around this? I read also something about using the
"export" keyword but it doesn't seem to work with gnu g++.
The export keyword is meant for this purpose, however, most compilers don't
support it.
Any help will be appreciated.
Your options include:
a) leave the implementation code in the header files. This is common
practice.
b) use a compiler that supports "export". This is not common and will render
you code less portable.
Best
Kai-Uwe Bux
Thanks for your reply. I'll go with option a) for now. Best regards.
aaragon,
Although this isn't removing it from #included headers, this is a good
way to separate the implementation from definition in files.
/////foo.hh
#ifndef FOO_HH
#define FOO_HH
template< typename TYPE >
void
foo( TYPE val ) ;
#include "foo.tcc"
#endif
////foo.tcc
#include <iostream>
template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;
}
////main.cc
#include "foo.hh"
int
main( int argc, char* argv[] )
{
foo( 1 ) ;
}
///End of example.
HTH,
Paul Davis
I would even suggest:
// export_support_begin.hh
#if defined(EXPORT)
#undef EXPORT
#if defined(EXPORT_KEYWORD_SUPPORT)
#define EXPORT export
#else
#define EXPORT
#endif
// export_support_end.hh
#undef EXPORT
// foo.hh
#ifndef FOO_HH
#define FOO_HH
#include "export_support_begin.hh"
EXPORT template< typename TYPE >
void
foo( TYPE val ) ;
#if !defined(EXPORT_KEYWORD_SUPPORT)
#include "foo.tcc"
#endif
#include "export_support_end.hh"
#endif
// foo.tcc
#include <iostream>
#include "foo.hh"
#include "export_support_begin.hh"
EXPORT template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;
}
#include "export_support_end.hh"
// main.cc
#include "foo.hh"
int
main( int argc, char* argv[] )
{
foo( 1 ) ;
}
That way you can define EXPORT_KEYWORD_SUPPORT on compilers that support the
export keyword (notably Comeau and other compilers that use the EDG front
end).
It is safe to compile foo.tcc even on a noncompliant compiler.
-dr
I dunno. That seems like an awful lot of work for rather little pay
off. I'm not entirely certain about how the export keyword works, but
I imagine all this would save is the redundant compilation of a
multiple templates with the same type parameters.
Paul Davis

Thought this was an interesting topic I haven't read enough about so I
googled around a bit and found a two articles about export. One for
and one against.

Against:http://std.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/n1426.pdf

For:http://www.comeaucomputing.com/iso/promises.html

Personally, I really don't see the motivation for a compiler to
support the feature other than to be fully standards conformant. The
article that was for keeping and requiring export did little to
convince me that export was a Good Thing (TM). In general the argument
seemed to be built on arguments that had little to do with the
theoretical aspects of why export is good and should be kept, instead
focusing on the fact that so much has already been put into it and its
not the only hard feature to implement.

The fact that this feature is so prohibitive to implement that major
compiler vendors aren't supporting it says something to me. I mean,
these people write *compilers* for a living. Although anecdotal and
trivial, how many features have made major compilers balk at
supporting them due to the prohibitively complex nature? I'd imagine
thats a fairly short list.
From what I've seen, all the 'odd' rules (e.g. koenig lookup) that

make up C++ have a very sound theoretical reason behind them. I
haven't found a good reason for supporting export other than the
original topic of separating template implementation from definition.

As always though, if someone can show me an example that will
absolutely not work without export I'd be happy to change my tune.
But until then, it seems like a waste of effort for compiler
developers.

Paul Davis

Thank you guys for all your insight on this. I appreciate it a lot.
 
A

aaragon

Thanks for your reply. I'll go with option a) for now. Best regards.

aaragon,

Although this isn't removing it from #included headers, this is a good
way to separate the implementation from definition in files.

/////foo.hh

#ifndef FOO_HH
#define FOO_HH

template< typename TYPE >
void
foo( TYPE val ) ;

#include "foo.tcc"

#endif

////foo.tcc

#include <iostream>

template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;

}

////main.cc

#include "foo.hh"

int
main( int argc, char* argv[] )
{
foo( 1 ) ;

}

///End of example.

HTH,

Paul Davis

Paul,

I've been trying to use your approach but I run into problems. When I
include the .cxx file at the end of the .h file then I receive the
compilation error:

file.cxx:9: error: redefinition of 'void ClassA<Objective,
StoragePolicy, k>::initialize()'
file.cxx:9: error: 'void ClassA<Objective, StoragePolicy,
k>::initialize()' previously declared here

I figured that this is because in the .cxx file I had the include of
the .h file so I was actually including the .cxx file twice. I removed
that include in the .cxx file and now the error is

file.cxx:9: error: expected initializer before '<' token

I have no clue why I have this message. I thought that it may be
because I need to compile the .h file instead of the .cxx file in the
Makefile but that doesn't make sense. Any suggestions?

a^2
 
P

paul.joseph.davis

Although this isn't removing it from #included headers, this is a good
way to separate the implementation from definition in files.

#ifndef FOO_HH
#define FOO_HH
template< typename TYPE >
void
foo( TYPE val ) ;
#include "foo.tcc"


#include <iostream>
template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;


#include "foo.hh"
int
main( int argc, char* argv[] )
{
foo( 1 ) ;

///End of example.

Paul Davis

Paul,

I've been trying to use your approach but I run into problems. When I
include the .cxx file at the end of the .h file then I receive the
compilation error:

file.cxx:9: error: redefinition of 'void ClassA<Objective,
StoragePolicy, k>::initialize()'
file.cxx:9: error: 'void ClassA<Objective, StoragePolicy,
k>::initialize()' previously declared here

I figured that this is because in the .cxx file I had the include of
the .h file so I was actually including the .cxx file twice. I removed
that include in the .cxx file and now the error is

file.cxx:9: error: expected initializer before '<' token

I have no clue why I have this message. I thought that it may be
because I need to compile the .h file instead of the .cxx file in the
Makefile but that doesn't make sense. Any suggestions?

a^2


Aaragon,

I can't tell for sure without actual file contents, but you're not
including code that just 'uses' the template right?

Ie, your included template file should *only* contain functions and/or
classes that are templates. As you found out, you should also only
included the templated header file by including the corresponding
header.

Your problem is a syntax error. I couldn't tell you why without
looking at the actual source.

HTH,

Paul
 
A

aaragon

aaragon wrote:
Hi everyone,
I've been writing some code and so far I have all the code written in
the .h files in order to avoid the linker errors. I'm using templates.
I wanted to move the implementations to the .cpp files. After some
reading, I found that the only way to do this is to add the actual
template instantiations in the .cpp file. But, how do you do that if
you're not working with built-in types? For example, a template class
might be,
template
<
class Objective,
class StoragePolicy,
int k
class ClassA {
...
// declarations and definitions
...
}
How do I separate this into .cpp and .h files if I Objective and
StoragePolicy are defined by the user of the code?
Short answer: you don't.
In this example,
StoragePolicy is something that I could define (let's say
std::vector), but Objective is an object that the user provides. Is
there a way to get around this? I read also something about using the
"export" keyword but it doesn't seem to work with gnu g++.
The export keyword is meant for this purpose, however, most compilers don't
support it.
Any help will be appreciated.
Your options include:
a) leave the implementation code in the header files. This is common
practice.
b) use a compiler that supports "export". This is not common and will render
you code less portable.
Best
Kai-Uwe Bux
Thanks for your reply. I'll go with option a) for now. Best regards.
aaragon,
Although this isn't removing it from #included headers, this is a good
way to separate the implementation from definition in files.
/////foo.hh
#ifndef FOO_HH
#define FOO_HH
template< typename TYPE >
void
foo( TYPE val ) ;
#include "foo.tcc"
#endif
////foo.tcc
#include <iostream>
template< typename TYPE >
void
foo( TYPE val )
{
std::cout << val << std::endl ;
}
////main.cc
#include "foo.hh"
int
main( int argc, char* argv[] )
{
foo( 1 ) ;
}
///End of example.
HTH,
Paul Davis

I've been trying to use your approach but I run into problems. When I
include the .cxx file at the end of the .h file then I receive the
compilation error:
file.cxx:9: error: redefinition of 'void ClassA<Objective,
StoragePolicy, k>::initialize()'
file.cxx:9: error: 'void ClassA<Objective, StoragePolicy,
k>::initialize()' previously declared here
I figured that this is because in the .cxx file I had the include of
the .h file so I was actually including the .cxx file twice. I removed
that include in the .cxx file and now the error is
file.cxx:9: error: expected initializer before '<' token
I have no clue why I have this message. I thought that it may be
because I need to compile the .h file instead of the .cxx file in the
Makefile but that doesn't make sense. Any suggestions?

Aaragon,

I can't tell for sure without actual file contents, but you're not
including code that just 'uses' the template right?

Ie, your included template file should *only* contain functions and/or
classes that are templates. As you found out, you should also only
included the templated header file by including the corresponding
header.

Your problem is a syntax error. I couldn't tell you why without
looking at the actual source.

HTH,

Paul

Well, I have all my code written in the .h files. Now, to try your
approach, I separated the definition of one function and it compiled
just fine when both the declaration AND the definition were on the .h
file. Something like this works fine:

// file.h
#ifndef CLASS_A_
#define CLASS_A_
template
<
class Objective,
class StoragePolicy,
int kclass ClassA{
void initialize();
}

template
<
class Objective,
class StoragePolicy,
int kvoid ClassA<Objective,StoragePolicy,k>::initialize()
{
// do something to initialize
}

#endif

// file.cpp
#include "file.h"
// file has nothing, everything defined in the .h file to avoid
linking problems


This works fine, it compiles and everything. Then, when I move the
code to the .cpp file it looks like this:

// file.h
#ifndef CLASS_A_
#define CLASS_A_
template
<
class Objective,
class StoragePolicy,
int kclass ClassA{
void initialize();
}
#include "file.cpp"
#endif

// file.cpp
template
<
class Objective,
class StoragePolicy,
int kvoid ClassA<Objective,StoragePolicy,k>::initialize()
{
// do something to initialize
}

Then I got this message
file.cpp:8: error: expected initializer before '<' token

I'm using autotools to produce the make file, and the Makefile.am
looks like

h_sources = file.h
cxx_sources = file.cpp

noinst_PROGRAMS = test.out
test_out_SOURCES = main.cxx

Maybe I should compile the .h file instead? I don't know what's going
on.
 
M

Marcus Kwok

aaragon said:
Well, I have all my code written in the .h files. Now, to try your
approach, I separated the definition of one function and it compiled
just fine when both the declaration AND the definition were on the .h
file. Something like this works fine:

[working code redacted]
This works fine, it compiles and everything. Then, when I move the
code to the .cpp file it looks like this:

// file.h
#ifndef CLASS_A_
#define CLASS_A_
template
<
class Objective,
class StoragePolicy,
int k
class ClassA{
void initialize();
}
#include "file.cpp"
#endif

// file.cpp
template
<
class Objective,
class StoragePolicy,
int k
void ClassA<Objective,StoragePolicy,k>::initialize()

Here, I believe you do not need to specify the template parameters
again, since you specified them in the lines above this.
{
// do something to initialize
}

Then I got this message
file.cpp:8: error: expected initializer before '<' token

This is probably what the error is telling you (hint: what is line 8 in
file.cpp?).
 
A

aaragon

aaragon said:
Well, I have all my code written in the .h files. Now, to try your
approach, I separated the definition of one function and it compiled
just fine when both the declaration AND the definition were on the .h
file. Something like this works fine:

[working code redacted]


This works fine, it compiles and everything. Then, when I move the
code to the .cpp file it looks like this:
// file.h
#ifndef CLASS_A_
#define CLASS_A_
template
<
class Objective,
class StoragePolicy,
int k
class ClassA{
void initialize();
}
#include "file.cpp"
#endif
// file.cpp
template
<
class Objective,
class StoragePolicy,
int k
void ClassA<Objective,StoragePolicy,k>::initialize()

Here, I believe you do not need to specify the template parameters
again, since you specified them in the lines above this.
{
// do something to initialize
}
Then I got this message
file.cpp:8: error: expected initializer before '<' token

This is probably what the error is telling you (hint: what is line 8 in
file.cpp?).

Well, I removed the <..> but I had other errors. You have to include
the <..> in the definition, at least with g++. The funny thing is that
I was able to compile at last! I just changed the Makefile.am so I
have

h_sources = file.h
cxx_sources = file.h

noinst_PROGRAMS = test.out
test_out_SOURCES = main.cxx

It was what I thought, I have to compile the .h file! I mean, if I
compile the .cpp file, there is no #include "file.h" file on the top
so the compiler never looks for that file. On the other hand, when
compiling the file.h, there is an #include "file.cpp" at the end so
everything is looked up by the compiler. Now, what's bothering me is
that this is a bad fix. It doesn't make sense to compile header files,
does it? However, it works and I don't need to deal with export
keywords or having ALL in the .h files.
Any other suggestions?
 
M

Marcus Kwok

aaragon said:
This works fine, it compiles and everything. Then, when I move the
code to the .cpp file it looks like this:

// file.h
#ifndef CLASS_A_
#define CLASS_A_
template
<
class Objective,
class StoragePolicy,
int k
class ClassA{
void initialize();
}
#include "file.cpp"
#endif

// file.cpp
template
<
class Objective,
class StoragePolicy,
int k
void ClassA<Objective,StoragePolicy,k>::initialize()
{
// do something to initialize
}

Then I got this message
file.cpp:8: error: expected initializer before '<' token

I'm using autotools to produce the make file, and the Makefile.am
looks like

h_sources = file.h
cxx_sources = file.cpp

noinst_PROGRAMS = test.out
test_out_SOURCES = main.cxx

Maybe I should compile the .h file instead? I don't know what's going
on.

Sorry it took so long to reply.

OK, my original example was flawed. This compiles and links fine for
me:

// template.h
#ifndef CLASS_A_
#define CLASS_A_

template
<
class Objective,
class StoragePolicy,
int kclass ClassA {
void initialize();
};

#include "template.cpp"

#endif


// template.cpp
#include "template.h"

template
<
class Objective,
class StoragePolicy,
int kvoid ClassA<Objective, StoragePolicy, k>::initialize()
{
// do something to initialize
}


// usage.cpp
#include "template.h"

int main()
{
ClassA<int, int, 1> a;
}


Then, you only need to compile usage.cpp. You do not need to explicitly
compile template.cpp by itself, which probably won't do you any good
unless you use the "export" keyword AND your compiler supports this
keyword (most don't).

The main point of this is just to have the implementation of your
templates in a separate file. You don't actually need to compile
template.cpp until you instantiate the template, which happens when you
use it. At that point, the definitions must be known, so they get
pulled in by #include "template.h" (which implicitly #includes
"template.cpp").
 
P

paul.joseph.davis

Sorry it took so long to reply.

OK, my original example was flawed. This compiles and links fine for
me:

// template.h
#ifndef CLASS_A_
#define CLASS_A_

template
<
class Objective,
class StoragePolicy,
int k

class ClassA {
void initialize();

};

#include "template.cpp"

#endif

// template.cpp
#include "template.h"

Just a minor point, but you probably don't need to #include the header
that #include's this template source file.
template
<
class Objective,
class StoragePolicy,
int k

void ClassA<Objective, StoragePolicy, k>::initialize()
{
// do something to initialize

}

// usage.cpp
#include "template.h"

int main()
{
ClassA<int, int, 1> a;

}

Then, you only need to compile usage.cpp. You do not need to explicitly
compile template.cpp by itself, which probably won't do you any good
unless you use the "export" keyword AND your compiler supports this
keyword (most don't).

The main point of this is just to have the implementation of your
templates in a separate file. You don't actually need to compile
template.cpp until you instantiate the template, which happens when you
use it. At that point, the definitions must be known, so they get
pulled in by #include "template.h" (which implicitly #includes
"template.cpp").

Exactly. Remember, we're not compiling template.cpp into a '.o' file
here. I specifically use a different extension for template definition
files (.tcc) to indicate that it shouldn't be compiled independantly.
This is just used so that you don't end up with template headers that
are thousands of lines long.

HTH,
Paul Davis
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top