Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

template classes and .h file

78 views
Skip to first unread message

asetof...@gmail.com

unread,
Sep 20, 2015, 12:30:33 AM9/20/15
to
If I have one library file in C++ one .dll:
Where I have to put one template class, in the .cpp file that is the
.dll or in the .h file I include
when I call that .dll from other
.cpp files?


[I think all in the .h file I use for call that .dll from other .cpp programs]

Paavo Helde

unread,
Sep 20, 2015, 3:43:33 AM9/20/15
to
asetof...@gmail.com wrote in
news:5a6d704d-8f2f-41cc...@googlegroups.com:
The most simple solution is to put all templates in header files. If most
code in a project is in templates, then it might even make sense to put
everything in header files and avoid creating a dll altogether. Such
libraries are called header-only libraries and for example Boost is full of
them.

See also https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl

hth
Paavo

Rosario19

unread,
Sep 21, 2015, 5:43:30 AM9/21/15
to
thank you

but it is possible put only dichiarations [member, functions,
operators etc] of the template class in the header file, and put all
the code of that member functions, operators etc of the template class
in the .dll file [in a way it is possible use that template class from
some other .cpp file]?

Rosario19

unread,
Sep 21, 2015, 6:11:13 AM9/21/15
to
On Mon, 21 Sep 2015 11:43:18 +0200, Rosario19 wrote:

>but it is possible put only dichiarations [member, functions,
>operators etc] of the template class in the header file, and put all
>the code of that member functions, operators etc of the template class
>in the .dll file [in a way it is possible use that template class from
>some other .cpp file]?

it seems to me
that this compile for the creation of the .dll

but when i want to use the compiler on other .cpp file that call one
instance of that template class...
the compiler says "unrisolved external" even if i put __extern in the
code of that template in the .dll

so i would use only the .h file for template....

but doing so there could be problem in call functions expecially
input/ output
where their definitions, in the few i understand, are in one other
file header afther, in include, the header where there is the template
class

Louis Krupp

unread,
Sep 21, 2015, 7:01:36 AM9/21/15
to
On Mon, 21 Sep 2015 12:11:04 +0200, Rosario19 <R...@invalid.invalid>
wrote:
If you could post two or three small files you're trying to compile
(and possibly link) along with the errors you're getting, I think it
would be helpful.

Louis

Paavo Helde

unread,
Sep 21, 2015, 11:11:26 AM9/21/15
to
Rosario19 <R...@invalid.invalid> wrote in
news:fflvvat2ln463bn0q...@4ax.com:

> On Mon, 21 Sep 2015 11:43:18 +0200, Rosario19 wrote:
>
>>but it is possible put only dichiarations [member, functions,
>>operators etc] of the template class in the header file, and put all
>>the code of that member functions, operators etc of the template class
>>in the .dll file [in a way it is possible use that template class from
>>some other .cpp file]?

Yes, to some extent, via explicit instantiations.

> it seems to me
> that this compile for the creation of the .dll
>
> but when i want to use the compiler on other .cpp file that call one
> instance of that template class...
> the compiler says "unrisolved external" even if i put __extern in the
> code of that template in the .dll
>
> so i would use only the .h file for template....

Ok, fine.

>
> but doing so there could be problem in call functions expecially
> input/ output
> where their definitions, in the few i understand, are in one other
> file header afther, in include, the header where there is the template
> class

Template classes should be included first. Template definitions can
access types and functions which are not yet declared, assuming that
these types and functions depend on the template parameters. Such names
are resolved in a later compilation stage, so there should be no problem.
Example:

template<class T>
class Foo: public T{
public:
int f() {
return T::bar; // bar not yet declared, OK (as it depends on T)
}
};

class A {
protected:
const static int bar = 42;
};

int main() {
Foo<A> a;
return a.f(); // ok
}

Note that leaving out T:: in f() would make the code invalid.

hth
Paavo

Rosario19

unread,
Sep 21, 2015, 1:18:32 PM9/21/15
to
i think is not possible put code of the class template in the ndll.cpp
file right?
[pheraps only the code of the template not use type <T>]
-----------------------
/*
FILE ndll.cpp
build the .dll and .lib
usare:
>bcc32 -v -WD ndll.cpp
>implib ndll.lib ndll.dll
*/


#include "fileI.h"
#include <stdio.h>
#include <stdarg.h>

int WINAPI
DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{(void) hinst; (void) lpReserved;
if(reason == DLL_PROCESS_ATTACH){}
else if(reason == DLL_PROCESS_DETACH){}
R 1;
}

int __export P(char* fmt, ... )
{va_list args;
int r;
va_start(args, fmt);
r=vfprintf(stderr, fmt, args);
va_end(args);
R r;
}

template<class T> __export permutazioni<T>::permutazioni(u32 a)
{u32 i;
n=0; arr=0; c=0; cnt=0; ji=0;
if(a==0||a>0xFF) {PBadAlloc=1; R;}
arr=(T*)MM( a*S(T) );
if(arr==0){PBadAlloc=1; R;}
c=(u32*)MM( a*S(u32) );
if(c==0){FF(arr); PBadAlloc=1; arr=0; R;}
n=a;
F(i=0; i<n; ++i){c[i]=0; arr[i]=i;}
}

template<class T> __export permutazioni<T>::~permutazioni(){FF(c);
FF(arr);}

template<class T> u32 __export permutazioni<T>::swp(T* a, u32 i, u32
j)
{T x;
if(i>=n||j>=n) R -1;
if(i==j) R 0;
x=a[i]; a[i]=a[j]; a[j]=x; ++cnt;
R 0;
}

template<class T> u32 __export permutazioni<T>::index(T* a)
{u32 r;
if(arr==0||a==0) R -1;
if( !(arr<=a&&a<arr+n) ) R -1;
r=a-arr;
if(r>0xFFFFFF) R -1;
r=r/S(T);
R r;
}

// b=a^-1 b[a]=I=1,2,3,4,5...n
// a= 1 3 2 (1->1, 2->3 3->2) b= 1 3 2
// i->j j->i
template<class T> i32 __export
permutazioni<T>::inverse(permutazioni<T>& a)
{u32 i;
T t;

if(arr==0||n!=a.n) R -1; // devono avere lo stesso n
F(i=0; i<n; ++i)
{t=a.arr[i];
if(!(0<=t&&t<n)) R -1;
arr[t]= i ; // deve essere arr[a.arr[i]]=i;
}
nextP(0); // azzera next permutation
}

/* from Sedgewick, result in arr [3!=6] */
template<class T> u32 __export permutazioni<T>::nextP(u32 a)
{u32 k;

if(a==0)
{F(k=0; k<n; ++k) c[k]=0;
ji=0; cnt=0;
R 1;
}
F( ; ji<n; )
{if(c[ji]<ji)
{swp(arr, ((ji+1)%2? 0: c[ji]) , ji);
++c[ji]; ji=1; // can be ok ji=0; too
R 1; // ok
}
else c[ji++]=0;
}
R 0; // for end
}


template<class T> i32 __export permutazioni<T>::e(void){R
PBadAlloc;}

template<class T> T& __export permutazioni<T>::operator[](i32 i){R
arr[i];}

template<class T> void __export permutazioni<T>::print(void)
{u32 i;
F(i=0; i<n; ++i)
if(i==0 ) cout<<"[ "<< arr[i]<<" ";
else if(i==n-1) cout<<arr[i]<<" ] ";
else cout<<arr[i]<<" ";
}

------------------------
/*FILE fileI.h */
#ifndef fileI
#define fileI

#ifndef fileII
#include "fileII.h"
#endif

class __export permutazioni;
int __export P(char* , ...);

#endif
---------------------------
/*FILE fileII.h */
#ifndef fileII
#define fileII

#include <stdlib.h>
#include <windows.h>

#define uns unsigned
#define u32 unsigned
#define u64 unsigned __int64
#define i32 int
#define i64 __int64
#define u16 unsigned short
#define u8 unsigned char
#define i8 char
#define i16 short
#define long_long __int64
#define d64 double

#define sdC __stdcall
#define ooo cout
#define S sizeof
#define MM malloc
#define FF free

#define F for
#define R return
#define W while
#define GG(a,b) if(a)goto b
#define G goto

#ifndef NULL
#define NULL ((char*)0)
#endif

template<class T> class permutazioni{

public:

permutazioni(u32 );
~permutazioni( );

u32 swp(T* , u32 , u32 );
u32 index(T* );

i32 inverse(permutazioni<T>& );
u32 nextP(u32 );
void print(void);
i32 e(void);
T& operator[](i32 );

u32 n; /* number of element index 0..n-1 */
T *arr; /* where they are */
u32 *c; /* index array for find next permutation*/
u32 ji; /* index for next permutation: nextP() */
u32 cnt; /* cnt%2?-1:1 sign of permutation nextP() return*/
/* if some allocation error for all permutation here 1 */
static u32 PBadAlloc;
};


template<class T> u32 permutazioni<T>::PBadAlloc=0;


template<class T> class permutazioni1{

public:
permutazioni1(u32 );
~permutazioni1( );

u32 swp(T* , u32 , u32 );
u32 index(T* );

i32 inverse(permutazioni1<T>& );
u32 nextP(u32 );
void print(void);
i32 e(void);
T& operator[](i32 );

u32 n; /* number of element index 0..n-1 */
T *arr; /* where they are */
u32 *c; /* index array for find next permutation*/
u32 ji; /* index for next permutation: nextP() */
u32 cnt; /* cnt%2?-1:1 sign of permutation nextP() return*/
/* if some allocation error for all permutation here 1 */
static u32 PBadAlloc;
};


template<class T> u32 permutazioni1<T>::PBadAlloc=0;

template<class T> __export permutazioni1<T>::permutazioni1(u32 a)
{u32 i;
n=0; arr=0; c=0; cnt=0; ji=0;
if(a==0||a>0xFF) {PBadAlloc=1; R;}
arr=(T*)MM( a*S(T) );
if(arr==0){PBadAlloc=1; R;}
c=(u32*)MM( a*S(u32) );
if(c==0){FF(arr); PBadAlloc=1; arr=0; R;}
n=a;
F(i=0; i<n; ++i){c[i]=0; arr[i]=i;}
}

template<class T> __export permutazioni1<T>::~permutazioni1(){FF(c);
FF(arr);}

template<class T> u32 __export permutazioni1<T>::swp(T* a, u32 i, u32
j)
{T x;
if(i>=n||j>=n) R -1;
if(i==j) R 0;
x=a[i]; a[i]=a[j]; a[j]=x; ++cnt;
R 0;
}

template<class T> u32 __export permutazioni1<T>::index(T* a)
{u32 r;
if(arr==0||a==0) R -1;
if( !(arr<=a&&a<arr+n) ) R -1;
r=a-arr;
if(r>0xFFFFFF) R -1;
r=r/S(T);
R r;
}

// b=a^-1 b[a]=I=1,2,3,4,5...n
// a= 1 3 2 (1->1, 2->3 3->2) b= 1 3 2
// i->j j->i
template<class T> i32 __export
permutazioni1<T>::inverse(permutazioni1<T>& a)
{u32 i;
T t;

if(arr==0||n!=a.n) R -1; // devono avere lo stesso n
F(i=0; i<n; ++i)
{t=a.arr[i];
if(!(0<=t&&t<n)) R -1;
arr[t]= i ; // deve essere arr[a.arr[i]]=i;
}
nextP(0); // azzera next permutation
}

/* from Sedgewick, result in arr [3!=6] */
template<class T> u32 __export permutazioni1<T>::nextP(u32 a)
{u32 k;

if(a==0)
{F(k=0; k<n; ++k) c[k]=0;
ji=0; cnt=0;
R 1;
}
F( ; ji<n; )
{if(c[ji]<ji)
{swp(arr, ((ji+1)%2? 0: c[ji]) , ji);
++c[ji]; ji=1; // can be ok ji=0; too
R 1; // ok
}
else c[ji++]=0;
}
R 0; // for end
}


template<class T> i32 __export permutazioni1<T>::e(void){R
PBadAlloc;}

template<class T> T& __export permutazioni1<T>::operator[](i32 i){R
arr[i];}

template<class T> void __export permutazioni1<T>::print(void)
{u32 i;
F(i=0; i<n; ++i)
if(i==0 ) cout<<"[ "<< arr[i]<<" ";
else if(i==n-1) cout<<arr[i]<<" ] ";
else cout<<arr[i]<<" ";
}

#endif
---------------------------
/*FILE fileIII.h */
#ifndef fileIII
#define fileIII

#ifndef fileII
#include "fileII.h"
#endif


class __import permutazioni;
int __import P(char* , ...);


#endif
--------------------------
/*
FILE fileCpp.cpp
>bcc32 -v fileCpp.cpp ndll.lib
not compile the first g() function
compile ok the second g() function
*/


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

//this not compile
i32 g(void)
{u32 i, r, j;
permutazioni<u32> m(3);
permutazioni<u8> v(4);
char *ptr="mare";

if(m.e()) R 0;
F(i=0; i<m.n; ++i)
m[i]=i;
F(;;){m.print();
GG( (r=m.nextP(1))==-1 || r==0, m1);
}
m1:
F(i=0; i<v.n; ++i)
v[i]=ptr[i];

F(;;){v.print();
GG( (r=v.nextP(1))==-1 || r==0, la);
}
la:
P("\n");
R 0;
}
/*
//this compile
i32 g(void)
{u32 i, r, j;
permutazioni1<u32> m(3);
permutazioni1<u8> v(4);
char *ptr="mare";

if(m.e()) R 0;
F(i=0; i<m.n; ++i)
m[i]=i;
F(;;){m.print();
GG( (r=m.nextP(1))==-1 || r==0, m1);
}
m1:
F(i=0; i<v.n; ++i)
v[i]=ptr[i];

F(;;){v.print();
GG( (r=v.nextP(1))==-1 || r==0, la);
}
la:
P("\n");
R 0;
}
*/


int main(void)
{g();
R 0;
}

Jens Thoms Toerring

unread,
Sep 21, 2015, 2:06:09 PM9/21/15
to
Yes. The compiler must be able to see the templated code for
function to be able to create the "real" code, i.e. with the
occurences of the template parameters replaces by the concrete
type! So if you declare something templated in a header file
to be used from a number of cpp file also the definitions must
be in the header file.

Here's a trivial example:

foo.h:
=============

#include <iostream>
template< typename T >
T foo( T const arg1, T const & arg2 );
=============

file1.cpp
=============
#inclue "foo.h"

extern void bar( );

template< typename T >
T foo( T const & arg1, T const & arg2 ) { return arg1 + arg2; }

int main( )
{
std::cout foo( 1.2, -3.9 ) << std::endl;
bar( );
}
=============

file2.cpp
=============
#include <string>
#inclue "foo.h"
void bar( )
{
std::cout << foo( std::string( "hello " ), std::string( "world" )
<< std::endl;
}
=============

If the compiler sees file1.cpp it can geneterate a foo() function
that accepts two doubles, but there's no reason for it to also
create one that accepts two std::strings (or whatever types that
templated function may ever be used with - there's no way it
could know that!). And when file2.cpp is compiled the compiler
doesn't know how to create the required foo() function that
accepts two std::strings since that's only defined in file1.cpp.

So, unless the templated stuff is restricted to a single source
(cpp) file, the definitions also must be in the header file to
tell the compiler how to generate the required code with con-
crete types.
Regards, Jens
--
\ Jens Thoms Toerring ___ j...@toerring.de
\__________________________ http://toerring.de

mark

unread,
Sep 21, 2015, 2:24:57 PM9/21/15
to
On 2015-09-21 11:43, Rosario19 wrote:
> but it is possible put only dichiarations [member, functions,
> operators etc] of the template class in the header file, and put all
> the code of that member functions, operators etc of the template class
> in the .dll file [in a way it is possible use that template class from
> some other .cpp file]?

This is only possible in a limited way. You need to use explicit
instantiation:

<http://en.cppreference.com/w/cpp/language/class_template#Explicit_instantiation>

So you need to know which types your template(s) will be used with and
perform explicit instantiations for those. Only the file where you do
those instantiations needs access to the template definitions.

mad...@acm.org

unread,
Sep 21, 2015, 2:45:35 PM9/21/15
to
Seems to me there are two issues here:
1) The sound practice of separating declarations into a .h (or .hpp) file, and the corresponding implementation in a .cpp file.
2) The fact that the compiler needs to see the implementation of a template at the point it is used in order to know how to instantiate the template.

One common solution with templates is to put the declarations in a header file that is #included wherever the template is to be used. Then put the implementation in a .cpp, or, more commonly, a .tpp file.

Then, at the bottom of the header file, just before the end of the header include guard, put #include implementation.tpp.

This gives the best of both worlds: physical separation of declarations and implementation for human readers, while the compiler sees everything it needs too.

Randy.

Rosario19

unread,
Sep 21, 2015, 6:19:27 PM9/21/15
to
On Mon, 21 Sep 2015 19:18:11 +0200, Rosario19 wrote:

i think that the win move is
put all possible code not dipend <T> type of the template in the dll
library file
and put all other in the .h file

the problem i had possible is one expansion of a macro as
#define ooo cout
....
#define cout thatandthis[0]
etc

Ian Collins

unread,
Sep 21, 2015, 6:43:07 PM9/21/15
to
Rosario19 wrote:
> On Mon, 21 Sep 2015 19:18:11 +0200, Rosario19 wrote:
>
> i think that the win move is
> put all possible code not dipend <T> type of the template in the dll
> library file
> and put all other in the .h file
>
> the problem i had possible is one expansion of a macro as
> #define ooo cout
> .....
> #define cout thatandthis[0]
> etc

That's an easy fix: don't use pointless macros...

--
Ian Collins

Rosario19

unread,
Sep 22, 2015, 11:31:47 AM9/22/15
to
i already fix it... it was only write
thahandthis[0] in the place of cout in the header file where was the
template class

but in other code cout is ok... possible in template classes some
#define macro expansion have some problem...

Rosario19

unread,
Sep 23, 2015, 3:10:42 AM9/23/15
to
On Tue, 22 Sep 2015 17:31:20 +0200, Rosario19 wrote:

>but in other code cout is ok... possible in template classes some
>#define macro expansion have some problem...

it is in the header file .h i use "cout" only in the template class

Paavo Helde

unread,
Sep 23, 2015, 3:58:38 AM9/23/15
to
Rosario19 <R...@invalid.invalid> wrote in
news:30k40bt77fks2ovs0...@4ax.com:
If you properly #include <iostream> and use std::cout (not "using namespace
std;" and cout) in that header, then that's OK.

Defining and using obscure short-named macros in a public header is never a
good idea.

Yes, your problems would be solved more easily with the 'export' feature of
C++98. Alas, it was removed from the C++11 standard because of
implementation difficulties and small overall gains.



0 new messages