template class and static member variables

M

mast2as

Hi guys

Here's the class I try to compile (see below). By itself when I have a
test.cc file for example that creates an object which is an instance of
the class SpectralProfile, it compiles fine.

1 / Now If I move the getSpectrumAtDistance( const T &dist ) method
definition in SpectralProfofile.cc let's say the compiler says

core/profile.cc:199: error: `kNumBins' was not declared in this scope
core/profile.cc:199: error: template argument 2 is invalid
core/profile.cc:200: error: ISO C++ forbids declaration of
`getSpectrumAtDistance' with no type
core/profile.cc:200: error: prototype for `int
wSubsurface::SpectralProfile<T>::getSpectrumAtDistance(const T&)' does
not match any in class `wSubsurface::SpectralProfile<T>'
core/profile.hh:229: error: candidate is: wSubsurface::Vector<T,
wSubsurface::SpectralProfile<T>::kNumBins>
wSubsurface::SpectralProfile<T>::getSpectrumAtDistance(const T&)
core/profile.cc:200: error: template definition of non-template `int
wSubsurface::SpectralProfile<T>::getSpectrumAtDistance(const T&)'

That's my first problem... I know a bit about instanciation of
templated class in the cc file (to avoid linking errors). So would that
apply to those static const variables in that case too ?

2/

Basically kStart kEnd ... don't really have to be templated... only the
other member variables need to be.

So my question is... is there a way i can make the static variables
'untemplated' while the other are. This way when I call the function
getSpectrumAtDistance( const T &dist ) i don't have to do:

Vector<float, SpectralProfile<float>::kNumBins> vec =
spectralProfile->getSpectrumAtDistance( 0.1f );

which is a bit cumbersone... but maybe there's no better option ?

Thank you

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template<typename T>
class SpectralProfile : public TProfile<T>
{
public:
static const T kStart = 400.0;
static const T kEnd = 700.0;
static const T kBinEvery = 2.0;
static const int kNumBins = static_cast<int>( ( kEnd - kStart ) /
kBinEvery + 1 );

T *m_spectrums; //!< Continuous chunk of mem that holds data

public:
SpectralProfile( const char * spectralProfileFile );
~SpectralProfile();

Vector<T, kNumBins> getSpectrumAtDistance( const T &dist )
{
if ( dist <= this->m_minDistance ) {
return Vector<T, kNumBins>( T( 0.0 ) );
}
else if ( dist > this->m_maxDistance ) {
return Vector<T, kNumBins>( m_spectrums + ( this->m_numSamples -
1 ) * kNumBins );
}
}
};
 
S

Salt_Peter

Hi guys

Here's the class I try to compile (see below). By itself when I have a
test.cc file for example that creates an object which is an instance of
the class SpectralProfile, it compiles fine.

Thats a surprise. The member function getSpectrumAtDistance(...) is not
static.
1 / Now If I move the getSpectrumAtDistance( const T &dist ) method
definition in SpectralProfofile.cc let's say the compiler says

You should keep the function inline, not in its implementation file.
Alternatively, you could specialize the template in the implementation
file.
Other options are in the faq.
http://www.parashift.com/c++-faq-lite/templates.html
read section 35-15
Any reason why you are compiling a *.cc file as opposed to a cpp?
core/profile.cc:199: error: `kNumBins' was not declared in this scope
core/profile.cc:199: error: template argument 2 is invalid
core/profile.cc:200: error: ISO C++ forbids declaration of
`getSpectrumAtDistance' with no type
core/profile.cc:200: error: prototype for `int
wSubsurface::SpectralProfile<T>::getSpectrumAtDistance(const T&)' does
not match any in class `wSubsurface::SpectralProfile<T>'
core/profile.hh:229: error: candidate is: wSubsurface::Vector<T,
wSubsurface::SpectralProfile<T>::kNumBins>
wSubsurface::SpectralProfile<T>::getSpectrumAtDistance(const T&)
core/profile.cc:200: error: template definition of non-template `int
wSubsurface::SpectralProfile<T>::getSpectrumAtDistance(const T&)'

That's my first problem... I know a bit about instanciation of
templated class in the cc file (to avoid linking errors). So would that
apply to those static const variables in that case too ?

Say you had a class labelled MyStatics:

// mystatics.h
template<typename T>
class MyStatics
{
static const T kStart;
static const T kEnd;
static const T kBinEvery;
static const int kNumBins;

T *m_spectrums; //!< Continuous chunk of mem that holds data
};

// mystatics.cpp
#include "mystatics.h"

template<typename T > const T MyStatics< T >::kStart = 400.0;
template<typename T > const T MyStatics< T >::kEnd = 700.0;
template<typename T > const T MyStatics< T >::kBinEvery = 2.0;
template<typename T > const int MyStatics< T >::kNumBins =
static_cast<int>( ( kEnd - kStart ) / kBinEvery + 1 );

// test.cpp
int main()
{
MyStatics<double> profile;
return 0;
}

Personally, i'ld make the members non-static and simply use a MyStatics
singleton.
2/

Basically kStart kEnd ... don't really have to be templated... only the
other member variables need to be.

and whats preventing you from doing that too?
So my question is... is there a way i can make the static variables
'untemplated' while the other are. This way when I call the function
getSpectrumAtDistance( const T &dist ) i don't have to do:

Vector<float, SpectralProfile<float>::kNumBins> vec =
spectralProfile->getSpectrumAtDistance( 0.1f );

which is a bit cumbersone... but maybe there's no better option ?

template< typename T >
class MyStatics
{
static const double kStart;
};

or

template< typename T = double >
class MyStatics
{
static const T kStart;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template<typename T>
class SpectralProfile : public TProfile<T>
{
public:
static const T kStart = 400.0;
static const T kEnd = 700.0;
static const T kBinEvery = 2.0;
static const int kNumBins = static_cast<int>( ( kEnd - kStart ) /
kBinEvery + 1 );

T *m_spectrums; //!< Continuous chunk of mem that holds data

public:
SpectralProfile( const char * spectralProfileFile );
~SpectralProfile();

Vector<T, kNumBins> getSpectrumAtDistance( const T &dist )

Only static functions are allowed to access static variables.
Declaring a member as static is rarely a warranted solution.
{
if ( dist <= this->m_minDistance ) {
return Vector<T, kNumBins>( T( 0.0 ) );
}
else if ( dist > this->m_maxDistance ) {
return Vector<T, kNumBins>( m_spectrums + ( this->m_numSamples -
1 ) * kNumBins );
}
}
};

Then there is the design of your class. Storing "chunks" of memory is
the old way of doing things. Specially when you end up transfering and
copying elements + platform padding. Why not store elements in
sequenced containers? Why aren't you using a std::vector of Ts? That
way you can have iterators, operators and streams do all the work for
you.
 
M

mast2as

Thanks a lot for your answer...
You should keep the function inline, not in its implementation file.
Alternatively, you could specialize the template in the implementation
file.
Other options are in the faq.
http://www.parashift.com/c++-faq-lite/templates.html
read section 35-15
okay...

Any reason why you are compiling a *.cc file as opposed to a cpp?

company's policy ;-) i don't like it much but our standard Makefile
forces the source code file to be names .hh and .cc
and whats preventing you from doing that too?

template< typename T >
class MyStatics
{
static const double kStart;
};

or

template< typename T = double >
class MyStatics
{
static const T kStart;
};

of course you are right ! I guess i need vacation...
Then there is the design of your class. Storing "chunks" of memory is
the old way of doing things. Specially when you end up transfering and
copying elements + platform padding. Why not store elements in
sequenced containers? Why aren't you using a std::vector of Ts? That
way you can have iterators, operators and streams do all the work for
you.

Ah ? Okay... I thought it was better that way... instead of having a
bunch of Vectors all other the place. I always thought in general an
application would run faster when the data it uses are located in the
same memory space. Will go back to Vectors then.

I also did that because I didn't like much the allocation of memory for
the Vectors. Since it's an array of Vectors I have to do the Vector<T,
Depth> **m_spectrums which is fine. The problem is when I need to
access the data of the Vectors. I have to do things like m_spectrum[ 10
]->w[ 12 ] (where w is the member variable of the Vector class that
hold the vector data). Or (*m_spectrum[10])[12] which is not very
elegant (as the Vector class has a [] operator that returns the value
in the w array at a certain index).

Anyway... thanks again
 
M

mast2as

Peter

While I am at it ?

Is there a reason why you ask about hh/cc vs hpp/cpp ? Do you have a
preference ?

Okay I ended up coding the class that (kNumBins) becomes basically
Depth in the class. Although I am forced at the end of the .cc file to
instance the class

template class SuperProfile<float, 3>;
template class SuperProfile<float, 151>;
template class SuperProfile<double, 3>;
template class SuperProfile<double, 151>;

I guess the float/double thing is not a problem but I am more annoyed
by the fact that I am limited in the size of the vector (3/151) at
compile time. Does it mean I have no way if I use this approach to
create on the fly a SuperProfile instance of size lets say 200 ?

template<int Depth> class SuperProfile<double, Depth>;

// then later in the code

SuperProfile<double, 200> aProfileVectorSize200; // That won't compile

In function `main':test.cc:(.text+0x24e): undefined reference to
`wSubsurface::SuperProfile<float, 200>::SuperProfile(char const*, int)'

Any idea how to bypass that problem ?

////////////////////////////////////////////////////////////////////////////////////////////

//
//! \brief Profile class
//

#ifndef _PROFILE_HH_
#define _PROFILE_HH_

#include "vector.hh"
#include "exception.hh"
#include "utils.hh"

// temp
//#include "ciexyz31.hh"

namespace wSubsurface {

template<typename T, int Depth>
class SuperProfile
{
public:
T *m_distances;
Vector<T, Depth> *m_spectrums;
int m_numSamples;
T m_minDistance;
T m_maxDistance;
public:
SuperProfile( const char *profileFile, int numSamples );
int binarySearch( const T &distance );
Vector<T, Depth> getSpectrumAtDistance( const T &dist );
};

} // end namespace

#endif // _PROFILE_HH_

//
//!\ brief Profile class, methods definitions
//

#include "profile.hh"
#include "exception.hh"

namespace wSubsurface {

template<typename T, int Depth>
SuperProfile<T, Depth>::SuperProfile( const char *profileFile,
int numSamples ) :
m_distances( NULL ),
m_spectrums( NULL ),
m_numSamples( numSamples ),
m_minDistance( T( 1.0e+6 ) ),
m_maxDistance( T( 0.0 ) )
{
// Read file
ifstream ifs;

try {
ifs.open( profileFile );
if ( ifs.fail() ) {
throw( Exception( "File doesn't exist", __FILE__, __LINE__ ) );
}
}
catch( const Exception &e ) {
cerr << e.what() << endl;
ifs.close();
}

int tmp; // remove that later
ifs.read( reinterpret_cast<char*>( &tmp ), sizeof( int ) );
ifs.read( reinterpret_cast<char*>( &tmp ), sizeof( int ) );
ifs.read( reinterpret_cast<char*>( &tmp ), sizeof( int ) );
ifs.read( reinterpret_cast<char*>( &tmp ), sizeof( int ) );

m_distances = new T[ m_numSamples ];
m_spectrums = new Vector<T, Depth>[ m_numSamples ];

for ( int i = 0; i < m_numSamples; ++i ) {
ifs.read( reinterpret_cast<char*>( &m_distances[ i ] ), sizeof( T )
);
ifs.read( reinterpret_cast<char*>( &m_spectrums[ i ].w[ 0 ] ),
sizeof( T ) * Depth );

if ( this->m_distances[ i ] < m_minDistance ) {
m_minDistance = m_distances[ i ];
}
else if ( this->m_distances[ i ] > this->m_maxDistance ) {
m_maxDistance = m_distances[ i ];
}
}

// Close file
ifs.close();
cerr << "num samples: " << m_numSamples << endl;
cerr << "min dist : " << m_minDistance << endl;
cerr << "max dist : " << m_maxDistance << endl;
}

template<typename T, int Depth>
int SuperProfile<T, Depth>::binarySearch( const T &distance )
//
//! \brief Returns array index of the closest distance.
//! \param distance is the distance we try to get the closest to
//! \return an index position in m_distances array to the closest
distance
//
{
// binary search
int first = 0, last = m_numSamples, middle = ( first + last ) / 2;

while( first < last ) {
if ( distance < m_distances[ middle ] ) {
last = middle - 1;
}
else if ( distance > m_distances[ middle ] ) {
first = middle + 1;
}
else {
return middle;
}
middle = ( first + last ) / 2;
}

return ( m_distances[ middle ] - distance > 0.0 ) ? middle - 1 :
middle;
}

template<typename T, int Depth>
Vector<T, Depth> SuperProfile<T, Depth>::getSpectrumAtDistance( const T
&dist )
{
if ( dist <= m_minDistance ) {
return Vector<T, Depth>( T( 0.0 ) );
}
else if ( dist > this->m_maxDistance ) {
return m_spectrums[ m_numSamples - 1 ];
}

int idx = binarySearch( dist );

T w = 0.5;

return m_spectrums[ idx ] * ( 1.0 - w ) + m_spectrums[ idx + 1 ] * w;
}

// instance
template class SuperProfile<float, 3>;
template class SuperProfile<float, 151>;
template class SuperProfile<double, 3>;
template class SuperProfile<double, 151>;

} // end of namespace
 
M

mast2as

Hum I should have added that I used

3 for a RGB color
151 because that's the size of the data that use if use a spectral
curve instead of RGB to describe a color.

So I guess I am fine with those 2 templates but it would be nice to
have a mechanisme where I can create one of the fly which has the size
that I want for the size of the Vector in case one day i use more or
less than 151 values for the spetral curve.

cheers -
 
S

Salt_Peter

Thanks a lot for your answer...


company's policy ;-) i don't like it much but our standard Makefile
forces the source code file to be names .hh and .cc


of course you are right ! I guess i need vacation...


Ah ? Okay... I thought it was better that way... instead of having a
bunch of Vectors all other the place. I always thought in general an
application would run faster when the data it uses are located in the
same memory space. Will go back to Vectors then.

A std::vector keeps its elements in contiguous memory. So, since
nothing stops you from making a vector of vectors...
I also did that because I didn't like much the allocation of memory for
the Vectors. Since it's an array of Vectors I have to do the Vector<T,
Depth> **m_spectrums which is fine. The problem is when I need to
access the data of the Vectors. I have to do things like m_spectrum[ 10
]->w[ 12 ] (where w is the member variable of the Vector class that
hold the vector data). Or (*m_spectrum[10])[12] which is not very
elegant (as the Vector class has a [] operator that returns the value
in the w array at a certain index).

Anyway... thanks again

A std::vector is actually an array on steroids. And you have a variety
of ways you can access the elements, including the operator[ ],
iterators as well as a panoply of powerfull algorithms. Its also a very
easy and safe container to use. Consider that it has the at(index)
accessor with out_of_range bounds check. The elements are allocated
and deallocated automatically, unless you choose to store pointers.

I'm not doing anything fancy:

#include <iostream>
#include <ostream>
#include <vector>

struct A // toy class
{
int n;
char c;
A() : n(0), c('a') { } // def ctor
A(size_t u, char c_) : n(static_cast<int>(u)), c(c_) { }
// overloaded operator<<
friend std::eek:stream&
operator<<(std::eek:stream& os, const A& r_a)
{
os << "n = " << r_a.n;
os << "\tc = " << r_a.c;
return os;
}
};

int main()
{
char mychar('a');
const size_t Size(10); // const Size
std::vector< A > va; // empty vector
for(size_t i = 0; i < Size; ++i)
{
va.push_back( A(i, mychar++) ); // push 0 to 10
}

for(size_t i = 0; i < Size; ++i)
{
std::cout << va << std::endl; // <- operator [ ]
}
std::vector< A > vanother(1000); // makes 1000 elements instantly
// no need to delete anything !
}

/*
n = 0 c = a
n = 1 c = b
n = 2 c = c
n = 3 c = d
n = 4 c = e
n = 5 c = f
n = 6 c = g
n = 7 c = h
n = 8 c = i
n = 9 c = j
*/

Whats the benefit? Once you learn how to use a std::vector...
all the other containers use nearly the same interface.
std::list, std::deque, etc

I'ld kindly suggest a book:
http://www.acceleratedcpp.com/
C++ Primer (4th Edition) Lippman, LaJoie, Moo
http://www.josuttis.com/ (C++ Standard Library)

All 3 are worth every penny and then some.
 

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,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top