Board index » cppbuilder » Class Template Linker Problem

Class Template Linker Problem


2005-06-13 08:20:22 PM
cppbuilder114
All,
When creating an instance of the Galios templated class the linker {*word*88}s.
Anyone know why? Use Project2.bpr.
I recieve the following linker problems:
[Linker Error] Unresolved external 'GaloisLongMultiplyTable<Galois<16,
69643, unsigned short>>::GaloisLongMultiplyTable<Galois<16, 69643, unsigned
short>>()' referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'ReedSolomon<Galois<16, 69643, unsigned
short>>::SetInput(const vector<bool, _STL::allocator<bool>>&)' referenced
from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2REPAIRER.OBJ
[Linker Error] Unresolved external 'Galois<16, 69643, unsigned
short>::pow(unsigned int) const' referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'Galois<16, 69643, unsigned
short>::Galois<16, 69643, unsigned short>(unsigned short)' referenced from
C:\PROGRAM FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'Galois<16, 69643, unsigned
short>::operator /=(const Galois<16, 69643, unsigned short>&)' referenced
from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'Galois<16, 69643, unsigned
short>::operator *(const Galois<16, 69643, unsigned short>&) const'
referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'ReedSolomon<Galois<16, 69643, unsigned
short>>::Process(unsigned int, unsigned long, const void *, unsigned long,
void *)' referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2REPAIRER.OBJ
Here is the class Galios:
Cpp File
#include "galois.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
// Construct the log and antilog tables from the generator
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galoistable<bits,generator,valuetype>::Galoistable(void)
{
u32 b = 1;
for (u32 l=0; l<Limit; l++)
{
log[b] = (ValueType)l;
antilog[l] = (ValueType)b;
b <<= 1;
if (b & Count) b ^= Generator;
}
log[0] = (ValueType)Limit;
antilog[Limit] = 0;
}
// The one and only galois log/antilog table object
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
Galoistable<bits,generator,valuetype>
Galois<bits,generator,valuetype>::table;
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>::Galois(typename
Galois<bits,generator,valuetype>::ValueType v)
{
value = v;
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::operator * (const
Galois<bits,generator,valuetype>&right) const
{
if (value == 0 || right.value == 0) return 0;
unsigned int sum = table.log[value] + table.log[right.value];
if (sum>= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>&
Galois<bits,generator,valuetype>::operator *= (const
Galois<bits,generator,valuetype>&right)
{
if (value == 0 || right.value == 0)
{
value = 0;
}
else
{
unsigned int sum = table.log[value] + table.log[right.value];
if (sum>= Limit)
{
value = table.antilog[sum-Limit];
}
else
{
value = table.antilog[sum];
}
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::operator / (const
Galois<bits,generator,valuetype>&right) const
{
if (value == 0) return 0;
assert(right.value != 0);
if (right.value == 0) {return 0;} // Division by 0!
int sum = table.log[value] - table.log[right.value];
if (sum < 0)
{
return table.antilog[sum+Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>&
Galois<bits,generator,valuetype>::operator /= (const
Galois<bits,generator,valuetype>&right)
{
if (value == 0) return *this;
assert(right.value != 0);
if (right.value == 0) {return *this;} // Division by 0!
int sum = table.log[value] - table.log[right.value];
if (sum < 0)
{
value = table.antilog[sum+Limit];
}
else
{
value = table.antilog[sum];
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::pow(unsigned int right) const
{
if (right == 0) return 1;
if (value == 0) return 0;
unsigned int sum = table.log[value] * right;
sum = (sum>>Bits) + (sum & Limit);
if (sum>= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::operator ^ (unsigned int right) const
{
if (right == 0) return 1;
if (value == 0) return 0;
unsigned int sum = table.log[value] * right;
sum = (sum>>Bits) + (sum & Limit);
if (sum>= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>&
Galois<bits,generator,valuetype>::operator ^= (unsigned int right)
{
if (right == 1) {value = 1; return *this;}
if (value == 0) return *this;
unsigned int sum = table.log[value] * right;
sum = (sum>>Bits) + (sum & Limit);
if (sum>= Limit)
{
value = table.antilog[sum-Limit];
}
else
{
value = table.antilog[sum];
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline valuetype Galois<bits,generator,valuetype>::Log(void) const
{
return table.log[value];
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline valuetype Galois<bits,generator,valuetype>::ALog(void) const
{
return table.antilog[value];
}
#ifdef LONGMULTIPLY
template <class g>
inline GaloisLongMultiplyTable<g>::GaloisLongMultiplyTable(void)
{
G *table = tables;
for (unsigned int i=0; i<Bytes; i++)
{
for (unsigned int j=i; j<Bytes; j++)
{
for (unsigned int ii=0; ii<256; ii++)
{
for (unsigned int jj=0; jj<256; jj++)
{
*table++ = G(ii << (8*i)) * G(jj << (8*j));
}
}
}
}
}
#endif
Header File:
#ifndef __GALOIS_H__
#define __GALOIS_H__
template <const unsigned int bits, const unsigned int generator, typename
valuetype>class Galoistable;
template <const unsigned int bits, const unsigned int generator, typename
valuetype>class Galois;
template <class g>class GaloisLongMultiplyTable;
// This source file defines the Galois object for carrying out
// arithmetic in GF(2^16) using the generator 0x1100B.
// Also defined are the Galoistable object (which contains log and
// anti log tables for use in multiplication and division), and
// the GaloisLongMultiplyTable object (which contains tables for
// carrying out multiplation of 16-bit galois numbers 8 bits at a time).
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galoistable
{
public:
typedef valuetype ValueType;
Galoistable(void);
enum
{
Bits = bits,
Count = 1<<Bits,
Limit = Count-1,
Generator = generator,
};
ValueType log[Count];
ValueType antilog[Count];
};
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galois
{
public:
typedef valuetype ValueType;
// Basic constructors
Galois(void) {};
Galois(ValueType v);
// Copy and assignment
Galois(const Galois &right) {value = right.value;}
Galois& operator = (const Galois &right) { value = right.value; return
*this;}
// Addition
Galois operator + (const Galois &right) const { return (value ^
right.value); }
Galois& operator += (const Galois &right) { value ^= right.value; return
*this;}
// Subtraction
Galois operator - (const Galois &right) const { return (value ^
right.value); }
Galois& operator -= (const Galois &right) { value ^= right.value; return
*this;}
// Multiplication
Galois operator * (const Galois &right) const;
Galois& operator *= (const Galois &right);
// Division
Galois operator / (const Galois &right) const;
Galois& operator /= (const Galois &right);
// Power
Galois pow(unsigned int right) const;
Galois operator ^ (unsigned int right) const;
Galois& operator ^= (unsigned int right);
// Cast to value and value access
operator ValueType(void) const {return value;}
ValueType Value(void) const {return value;}
// Direct log and antilog
ValueType Log(void) const;
ValueType ALog(void) const;
enum
{
Bits = Galoistable<bits,generator,valuetype>::Bits,
Count = Galoistable<bits,generator,valuetype>::Count,
Limit = Galoistable<bits,generator,valuetype>::Limit,
};
protected:
ValueType value;
static Galoistable<bits,generator,valuetype>table;
};
#ifdef LONGMULTIPLY
template <class g>
class GaloisLongMultiplyTable
{
public:
GaloisLongMultiplyTable(void);
typedef g G;
enum
{
Bytes = ((G::Bits + 7)>>3),
Count = ((Bytes * (Bytes+1)) / 2),
};
G tables[Count * 256 * 256];
};
#endif
typedef Galois<8,0x11D,u8>Galois8;
typedef Galois<16,0x1100B,u16>Galois16;
#endif // __GALOIS_H__
TIA,
John
 
 

Re:Class Template Linker Problem

John Borchers wrote:
Quote
When creating an instance of the Galios templated class the linker
{*word*88}s. Anyone know why? Use Project2.bpr.

I recieve the following linker problems:

[Linker Error] Unresolved external 'GaloisLongMultiplyTable<Galois<16,
69643, unsigned short>>::GaloisLongMultiplyTable<Galois<16, 69643,
unsigned short>>()' referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'ReedSolomon<Galois<16, 69643,
unsigned short>>::SetInput(const vector<bool, _STL::allocator<bool>
>&)' referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2REPAIRER.OBJ
[Linker Error] Unresolved external 'Galois<16, 69643, unsigned
short>::pow(unsigned int) const' referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'Galois<16, 69643, unsigned
short>::Galois<16, 69643, unsigned short>(unsigned short)' referenced
from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'Galois<16, 69643, unsigned
short>::operator /=(const Galois<16, 69643, unsigned short>&)'
referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'Galois<16, 69643, unsigned
short>::operator *(const Galois<16, 69643, unsigned short>&) const'
referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2CREATOR.OBJ
[Linker Error] Unresolved external 'ReedSolomon<Galois<16, 69643,
unsigned short>>::Process(unsigned int, unsigned long, const void *,
unsigned long, void *)' referenced from C:\PROGRAM
FILES\BORLAND\CBUILDER6\PROJECTS\PAR2CMDLINE-0.4\PAR2REPAIRER.OBJ
[ snip lots of code]
It looks to me that you are declaring function templates in your
header, and then implementing them in a .cpp and hoping to link those
definitions with the rest of your project, just as with non-template
functions.
Unfortunately, the C++ language does not support that. The concept of
separate compilation of templates turns out to be incredibly difficult
to implement, so the C++ Standards Comittee created a special keyword
to allow the compiler to do just that, 'export'. If you want to put
your template implementations in a separate cpp file, you are going to
need to use this keyword.
And that is where the news gets really bad!
Not only are templates so hard to implement that they got a special
keyword, even the keyword is hard to implement, so very few compilers
support it today. In particular, neither Borland, Microsoft, Intel,
Metrowerks nor Gnu (gcc) implement it. The only implementation I know
of comes from Comeau computing.
But that doesn't solve your problem <g>
I'm afraid the answer today is to put all the code from your cpp file
into the header. Yes, that does mean exposing additional dependencies,
and asking the compiler to scan a lot more code every time it compiles.
OTOH, it will work with most currently available compilers. That is
how the C++ Standard library is distrubuted too.
AlisdairM(TeamB)
 

Re:Class Template Linker Problem

I had tried that at first but here the compiler complains and I couldn't
figure out why either.
[C++ Error] galois.h(247): E2316 'log' is not a member of
'Galoistable<bits,generator,unsigned char>'
[Snippet]
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::pow(unsigned int right) const
{
if (right == 0) return 1;
if (value == 0) return 0;
Quote
>>This line unsigned int sum = table.log[value] * right;
[End of snippet]
But if you look at the Galiostable class, it is defined. It also compiles
when those functions are in the cpp file. Moved back to the header file it
doesn't compile. What is the compiler complaining about? I don't get it.
Source below as all .h to simplify cut and paste trials.
#ifndef __GALOIS_H__
#define __GALOIS_H__
template <const unsigned int bits, const unsigned int generator, typename
valuetype>class Galoistable;
template <const unsigned int bits, const unsigned int generator, typename
valuetype>class Galois;
template <class g>class GaloisLongMultiplyTable;
// This source file defines the Galois object for carrying out
// arithmetic in GF(2^16) using the generator 0x1100B.
// Also defined are the Galoistable object (which contains log and
// anti log tables for use in multiplication and division), and
// the GaloisLongMultiplyTable object (which contains tables for
// carrying out multiplation of 16-bit galois numbers 8 bits at a time).
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galoistable
{
public:
typedef valuetype ValueType;
Galoistable(void);
enum
{
Bits = bits,
Count = 1<<Bits,
Limit = Count-1,
Generator = generator,
};
ValueType log[Count];
ValueType antilog[Count];
};
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galois
{
public:
typedef valuetype ValueType;
// Basic constructors
Galois(void) {};
Galois(ValueType v);
// Copy and assignment
Galois(const Galois &right) {value = right.value;}
Galois& operator = (const Galois &right) { value = right.value; return
*this;}
// Addition
Galois operator + (const Galois &right) const { return (value ^
right.value); }
Galois& operator += (const Galois &right) { value ^= right.value; return
*this;}
// Subtraction
Galois operator - (const Galois &right) const { return (value ^
right.value); }
Galois& operator -= (const Galois &right) { value ^= right.value; return
*this;}
// Multiplication
Galois operator * (const Galois &right) const;
Galois& operator *= (const Galois &right);
// Division
Galois operator / (const Galois &right) const;
Galois& operator /= (const Galois &right);
// Power
Galois pow(unsigned int right) const;
Galois operator ^ (unsigned int right) const;
Galois& operator ^= (unsigned int right);
// Cast to value and value access
operator ValueType(void) const {return value;}
ValueType Value(void) const {return value;}
// Direct log and antilog
ValueType Log(void) const;
ValueType ALog(void) const;
enum
{
Bits = Galoistable<bits,generator,valuetype>::Bits,
Count = Galoistable<bits,generator,valuetype>::Count,
Limit = Galoistable<bits,generator,valuetype>::Limit,
};
protected:
ValueType value;
static Galoistable<bits,generator,valuetype>table;
};
#ifdef LONGMULTIPLY
template <class g>
class GaloisLongMultiplyTable
{
public:
GaloisLongMultiplyTable(void);
typedef g G;
enum
{
Bytes = ((G::Bits + 7)>>3),
Count = ((Bytes * (Bytes+1)) / 2),
};
G tables[Count * 256 * 256];
};
#endif
// Construct the log and antilog tables from the generator
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galoistable<bits,generator,valuetype>::Galoistable(void)
{
u32 b = 1;
for (u32 l=0; l<Limit; l++)
{
log[b] = (ValueType)l;
antilog[l] = (ValueType)b;
b <<= 1;
if (b & Count) b ^= Generator;
}
log[0] = (ValueType)Limit;
antilog[Limit] = 0;
}
// The one and only galois log/antilog table object
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
Galoistable<bits,generator,valuetype>
Galois<bits,generator,valuetype>::table;
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>::Galois(typename
Galois<bits,generator,valuetype>::ValueType v)
{
value = v;
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::operator * (const
Galois<bits,generator,valuetype>&right) const
{
if (value == 0 || right.value == 0) return 0;
unsigned int sum = table.log[value] + table.log[right.value];
if (sum>= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>&
Galois<bits,generator,valuetype>::operator *= (const
Galois<bits,generator,valuetype>&right)
{
if (value == 0 || right.value == 0)
{
value = 0;
}
else
{
unsigned int sum = table.log[value] + table.log[right.value];
if (sum>= Limit)
{
value = table.antilog[sum-Limit];
}
else
{
value = table.antilog[sum];
}
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::operator / (const
Galois<bits,generator,valuetype>&right) const
{
if (value == 0) return 0;
assert(right.value != 0);
if (right.value == 0) {return 0;} // Division by 0!
int sum = table.log[value] - table.log[right.value];
if (sum < 0)
{
return table.antilog[sum+Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>&
Galois<bits,generator,valuetype>::operator /= (const
Galois<bits,generator,valuetype>&right)
{
if (value == 0) return *this;
assert(right.value != 0);
if (right.value == 0) {return *this;} // Division by 0!
int sum = table.log[value] - table.log[right.value];
if (sum < 0)
{
value = table.antilog[sum+Limit];
}
else
{
value = table.antilog[sum];
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::pow(unsigned int right) const
{
if (right == 0) return 1;
if (value == 0) return 0;
unsigned int sum = table.log[value] * right;
sum = (sum>>Bits) + (sum & Limit);
if (sum>= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>
Galois<bits,generator,valuetype>::operator ^ (unsigned int right) const
{
if (right == 0) return 1;
if (value == 0) return 0;
unsigned int sum = table.log[value] * right;
sum = (sum>>Bits) + (sum & Limit);
if (sum>= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galois<bits,generator,valuetype>&
Galois<bits,generator,valuetype>::operator ^= (unsigned int right)
{
if (right == 1) {value = 1; return *this;}
if (value == 0) return *this;
unsigned int sum = table.log[value] * right;
sum = (sum>>Bits) + (sum & Limit);
if (sum>= Limit)
{
value = table.antilog[sum-Limit];
}
else
{
value = table.antilog[sum];
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline valuetype Galois<bits,generator,valuetype>::Log(void) const
{
return table.log[value];
}
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline valuetype Galois<bits,generator,valuetype>::ALog(void) const
{
return table.antilog[value];
}
#ifdef LONGMULTIPLY
template <class g>
inline GaloisLongMultiplyTable<g>::GaloisLongMultiplyTable(void)
{
G *table = tables;
for (unsigned int i=0; i<Bytes; i++)
{
for (unsigned int j=i; j<Bytes; j++)
{
for (unsigned int ii=0; ii<256; ii++)
{
for (unsigned int jj=0; jj<256; jj++)
{
*table++ = G(ii << (8*i)) * G(jj << (8*j));
}
}
}
}
}
#endif
typedef Galois<8,0x11D,u8>Galois8;
typedef Galois<16,0x1100B,u16>Galois16;
#endif // __GALOIS_H__
 

{smallsort}

Re:Class Template Linker Problem

Hi,
May explicit instantiation help?
Quote
I had tried that at first but here the compiler complains and I couldn't
figure out why either.

<skip>
 

Re:Class Template Linker Problem

Serge,
It might, but I don't know what that means.
John
"Serge Skorokhodov" < XXXX@XXXXX.COM >wrote in message
Quote
Hi,

May explicit instantiation help?

>I had tried that at first but here the compiler complains and I couldn't
>figure out why either.
>
<skip>
 

Re:Class Template Linker Problem

If you make a template declaration like this:
template <class T>
class AClass
{
public:
AClass(T a, T b);
...
};
Just add a line[s] into a cpp file:
class AClass<int>;
class AClass<double>;
...
class AClass<AnotherClass>;
and so on for each template instantiation you need. This force
compiler instantiate corresponding templates and then linker will
be able to find them.
I cam make some mistakes;) so just read about explicit template
instantiation topics in online C++Builder help and some C++ guide;)
Quote
It might, but I don't know what that means.

>May explicit instantiation help?
>
>
>>I had tried that at first but here the compiler complains and I couldn't
>>figure out why either.
>>
 

Re:Class Template Linker Problem

Serge Skorokhodov < XXXX@XXXXX.COM >writes:
Quote
template <class T>
class AClass
{
public:
AClass(T a, T b);
...
};

Just add a line[s] into a cpp file:

class AClass<int>;
class AClass<double>;
...
An explicit instantiation requires the template keyword:
template class AClass<int>;
template class AClass<double>;
(Or, I should say, the C++ language requires this, though some
compilers permit it either way. But some more strict compilers are
less forgiving.)
--
Chris (TeamB);
 

Re:Class Template Linker Problem

Chris or Serge,
This should be before the class declaration right?
Thanks,
John
"Chris Uzdavinis (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
Serge Skorokhodov < XXXX@XXXXX.COM >writes:

>template <class T>
>class AClass
>{
>public:
>AClass(T a, T b);
>...
>};
>
>Just add a line[s] into a cpp file:
>
>class AClass<int>;
>class AClass<double>;
>...

An explicit instantiation requires the template keyword:

template class AClass<int>;
template class AClass<double>;

(Or, I should say, the C++ language requires this, though some
compilers permit it either way. But some more strict compilers are
less forgiving.)

--
Chris (TeamB);
 

Re:Class Template Linker Problem

"John Borchers" < XXXX@XXXXX.COM >writes:
Quote
Chris or Serge,

This should be before the class declaration right?
No, to instantiate a template, the class not only has to be declared,
but it must also be defined.
You can put an explicit instantiation in a .cpp file that includes
your template header.
--
Chris (TeamB);
 

Re:Class Template Linker Problem

Quote
>template <class T>
>class AClass
>{
>public:
>AClass(T a, T b);
>...
>};
>
>Just add a line[s] into a cpp file:
>
>class AClass<int>;
>class AClass<double>;
>...

An explicit instantiation requires the template keyword:

template class AClass<int>;
template class AClass<double>;

(Or, I should say, the C++ language requires this, though some
compilers permit it either way. But some more strict compilers are
less forgiving.)

Absolutely! Thanks for correction. But I've made a disclamer...;)
 

Re:Class Template Linker Problem

Chris or Serge,
I still can't get the code to compile. Unfortunately, I'm trying to import
something that was GCC GNU (I think). Additionally I have done very limited
work with templates.
If I add these lines to the CPP file:
template class Galois <const unsigned int, const unsigned int, typename>;
template class Galoistable <const unsigned int, const unsigned int,
typename>;
The compiler {*word*88}s because of the typename.
[C++ Error] galois.cpp(30): E2439 'typename' is only allowed in template
declarations.
Currently there is nothing in the CPP file. There are two template classes
and inline functions in the header. For some reason it doesn't compile in
builder but apparently people have had success in MSVC.
Any ideas?
John
 

Re:Class Template Linker Problem

"John" < XXXX@XXXXX.COM >wrote in message
Quote
Chris or Serge,
:)
Quote
I still can't get the code to compile. Unfortunately, I'm trying to import
actualy your code is just a little too comlex for BCB compiler.
You need to simplify it, for examle, instead two separate templates with
long lists of parameters
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galoistable
{
...
};
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galois
{
public:
typedef valuetype ValueType;
// Basic constructors
Galois(void) {};
Galois(ValueType v);
...
};
try to define Galoistable as a nested class of the Galois, i.e
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galois
{
public:
typedef valuetype ValueType;
struct Table
{
Table();
enum
{
Bits = bits,
Count = 1<<Bits,
Limit = Count-1,
Generator = generator
};
ValueType log[Count];
ValueType antilog[Count];
};
// Basic constructors
Galois(void) {};
Galois(ValueType v);
...
};
I was able compiling your code after this change.
Another way to simplify this code is to replace three parameters with one.
For example, create additional structure
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
struct GaloisArg
{
typedef valuetype ValueType;
enum
{
Bits = bits,
Count = 1<<Bits,
Limit = Count-1,
Generator = generator,
};
};
which will be parameter for your Galois... templates
template <class Arg>
class Galoistable
: public Arg
{
public:
typedef typename Arg::ValueType ValueType;
Galoistable(void);
ValueType log[Arg::Count];
ValueType antilog[Arg::Count];
};
do similar procedure with Galois, update all functions (they will be much
shorter)
and then you can instantiate this template
int main()
{
Galois< GaloisArg<16,0x1100B,u16>>g;
g.pow(3);
}
and of course you can use both changes together
Quote
something that was GCC GNU (I think). Additionally I have done very
limited work with templates.

If I add these lines to the CPP file:

template class Galois <const unsigned int, const unsigned int, typename>;
template class Galoistable <const unsigned int, const unsigned int,
typename>;
to explicitely instantiate the template you should provide actual
parameters, for your original code it should look like
template class Galois<8,0x11D,u8>;
template class Galois<16,0x1100B,u16>;
because this was first thing I tried with your code, I can tell you
that in this case explicit instantiation does not help
Cheers,
Serge
 

Re:Class Template Linker Problem

Sergiy,
Thanks very much. I will study your response.
John
"Sergiy Kanilo" < XXXX@XXXXX.COM >wrote in message
Quote

"John" < XXXX@XXXXX.COM >wrote in message
news:42b757b0$ XXXX@XXXXX.COM ...
>Chris or Serge,

:)

>I still can't get the code to compile. Unfortunately, I'm trying to
>import

actualy your code is just a little too comlex for BCB compiler.
You need to simplify it, for examle, instead two separate templates with
long lists of parameters

template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galoistable
{
...
};

template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galois
{
public:
typedef valuetype ValueType;

// Basic constructors
Galois(void) {};
Galois(ValueType v);
...
};

try to define Galoistable as a nested class of the Galois, i.e

template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galois
{
public:
typedef valuetype ValueType;

struct Table
{
Table();

enum
{
Bits = bits,
Count = 1<<Bits,
Limit = Count-1,
Generator = generator
};

ValueType log[Count];
ValueType antilog[Count];
};

// Basic constructors
Galois(void) {};
Galois(ValueType v);
...
};

I was able compiling your code after this change.

Another way to simplify this code is to replace three parameters with one.
For example, create additional structure

template <const unsigned int bits, const unsigned int generator, typename
valuetype>
struct GaloisArg
{
typedef valuetype ValueType;

enum
{
Bits = bits,
Count = 1<<Bits,
Limit = Count-1,
Generator = generator,
};

};

which will be parameter for your Galois... templates

template <class Arg>
class Galoistable
: public Arg
{
public:
typedef typename Arg::ValueType ValueType;

Galoistable(void);

ValueType log[Arg::Count];
ValueType antilog[Arg::Count];
};

do similar procedure with Galois, update all functions (they will be much
shorter)
and then you can instantiate this template

int main()
{
Galois< GaloisArg<16,0x1100B,u16>>g;
g.pow(3);
}


and of course you can use both changes together

>something that was GCC GNU (I think). Additionally I have done very
>limited work with templates.
>
>If I add these lines to the CPP file:
>
>template class Galois <const unsigned int, const unsigned int, typename>;
>template class Galoistable <const unsigned int, const unsigned int,
>typename>;

to explicitely instantiate the template you should provide actual
parameters, for your original code it should look like

template class Galois<8,0x11D,u8>;
template class Galois<16,0x1100B,u16>;

because this was first thing I tried with your code, I can tell you
that in this case explicit instantiation does not help

Cheers,
Serge


 

Re:Class Template Linker Problem

Serge,
Still stuck but I'm understanding why it didn't want to work.
What I have now is:
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
class Galois
{
public:
typedef valuetype ValueType;
struct Table
{
Table();
enum
{
Bits=bits,
Count=1<<Bits,
Limit=Count-1,
Generator=generator
};
ValueType log[Count];
ValueType antilog[Count];
};
..functions ommitted..
enum
{
Bits = Table<bits,generator,valuetype>::Bits,
Count = Table<bits,generator,valuetype>::Count,
Limit = Table<bits,generator,valuetype>::Limit,
};
protected:
ValueType value;
static Table table;
};
I'm now tripping on what used to be the function (I commented out the entire
Galoistable class)
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galoistable<bits,generator,valuetype>::Galoistable(void)
[C++ Error] galois.h(153): E2102 Cannot use template
'Galois<bits,generator,valuetype>' without specifying specialization
parameters
Quote
>>template <const unsigned int bits, const unsigned int generator,
>>typename valuetype>
inline Galois::Table(void)
{
u32 b = 1;
for (u32 l=0; l<Limit; l++)
{
log[b] = (ValueType)l;
antilog[l] = (ValueType)b;
b <<= 1;
if (b & Count) b ^= Generator;
}
log[0] = (ValueType)Limit;
antilog[Limit] = 0;
}
TIA,
John
 

Re:Class Template Linker Problem

"John Borchers" < XXXX@XXXXX.COM >writes:
...
Quote
(I commented out the entire Galoistable class)
You commented out the Galoistable class?
Quote
template <const unsigned int bits, const unsigned int generator, typename
valuetype>
inline Galoistable<bits,generator,valuetype>::Galoistable(void)
But you're trying to use it here. Hmmm. That shouldn't work.
If I'm misreading your post, could you give a less broken-up example
of code so that I can cut-and-paste it to see the same error you're
seeing? (But please keep it as short.)
Thanks.
--
Chris (TeamB);