having linking troubles

I

Improving

I have a template class that has static members, so in the .cpp file I
have defined them with templated definitions. Now when in a different
..cpp file that includes the header file for the template class I derive
a new class from the template class and pass that class as its template
parameter (CRTP). Now when I instantiate this new class it complains it
cannot find the statics. Doesnt the template definition define them?
The code compiles fine but causes linker errors.
heres a boiled down example of whats causing the trouble....

header....
#ifndef CTYPE
#define CTYPE
#include <cstddef>
namespace ns
{
template <typename CT>
class OC
{
public:
static std::size_t count()
{
return OC<CT>::c_;
}
protected:
OC()
{
++OC<CT >::c_;
}
OC( const OC< CT >& )
{
++OC< CT >::c_;
}
~OC()
{
--OC< CT >::c_;
}
private:
static std::size_t c_;
};
}
#endif

..cpp ....
#include "templates.h"

namespace ns
{
// mandatory static definition
template < typename CT >
std::size_t OC< CT >::c_ = 0;
}

main.cpp
#include "templates.h"
#include <iostream>
using namespace std;

class C : private ns::OC<C>
{
public:
using ns::OC<C>::count;
};

int main()
{
C array[3];
cout << C::count()<<endl;
return 0;
}

How do I make my code linkable as well as compileable?
 
J

John Harrison

Improving said:
I have a template class that has static members, so in the .cpp file I
have defined them with templated definitions.

This is wrong, all template code must go in header files, that includes
static members.

john
 
I

Improving

wont that cause trouble with redefinitions if I link together two
different translation units both using the same class?
 
J

John Harrison

Improving said:
wont that cause trouble with redefinitions if I link together two
different translation units both using the same class?

No, templates are different. I know it seems strange but it's the right
thing to do. All template code goes in header files, the linker will
know to eliminate duplicate definitions.

Try reading the FAQ

http://www.parashift.com/c++-faq-lite/templates.html

question 35.7 onwards.

john
 
I

Improving

sorry thats lnk2001. Im getting one for each static member even though
I have moved the definitions to just below the class in the header
files. I dont understand whats going wrong here.
 
J

John Harrison

Improving said:
sorry thats lnk2001. Im getting one for each static member even though
I have moved the definitions to just below the class in the header
files. I dont understand whats going wrong here.

I took your code, put everything in the header file, and it worked for
me. I'm using MSVC++ 7.1

john
 
I

Improving

msvc 7 here.
can you try these john. sorry for length.

criticalsection.h

#ifndef CRITICALSECTION_090171
#define CRITICALSECTION_090171
#include <windows.h>

namespace threading
{
class CriticalSection
{
public:
CriticalSection()
{
InitializeCriticalSection(&lock_);
}
~CriticalSection()
{
DeleteCriticalSection(&lock_);
}
void enter()
{
EnterCriticalSection(&lock_);
}
void leave()
{
LeaveCriticalSection(&lock_);
}

private:
// disallow copying operations because they make no sense.
CriticalSection( const CriticalSection& );
CriticalSection& operator =( const CriticalSection& );

CRITICAL_SECTION lock_;
};

class Guard
{
public:
Guard(CriticalSection& lock) : lock_( lock )
{
lock_.enter();
}
~Guard()
{
lock_.leave();
}
private:
// disallow copying as again its senseless.
Guard( const Guard& );
Guard& operator =( const Guard& );

CriticalSection& lock_;
};

} // end namespace threading

#endif //inclusion guard

counted_type.h

#ifndef COUNTEDTYPE_090171
#define COUNTEDTYPE_090171
#include <cstddef>
#include <windows.h>
#include "criticalsection.h"

namespace utility
{
// A template class to generically count objects safely in a
multithreaded app.
template < typename CountedType >
class ObjectCounter
{
public:
static std::size_t count()
{
threading::Guard guard( lock_ );
return ObjectCounter< CountedType >::count_;
}
protected:
ObjectCounter()
{
threading::Guard guard( lock_ );
++ObjectCounter< CountedType >::count_;
}
ObjectCounter( const ObjectCounter< CountedType >& )
{
threading::Guard( lock_ );
++ObjectCounter< CountedType >::count_;
}
~ObjectCounter()
{
threading::Guard( lock_ );
--ObjectCounter< CountedType >::count_;
}
private:
static std::size_t count_;
static threading::CriticalSection lock_;
};

template said:
template < typename CountedType >
std::size_t ObjectCounter< CountedType >::count_ = 0;

} // end namespace utility
#endif // inclusion guard

limited_type.h

#ifndef LIMITEDTYPE_090171
#define LIMITEDTYPE_090171
#include <cstddef>
#include <stdexcept>
#include <string>
#include <windows.h>
#include "criticalsection.h"
#include "object_counter.h"

namespace utility
{
class TooManyObjects : public std::runtime_error
{
public:
TooManyObjects( const std::string& problem )
: runtime_error( problem )
{;}
};

// A template class that manages numbers of objects and ensures they
dont exceed
// the held maximum value.
template < typename CountedType >
class LimitedType : private ObjectCounter< CountedType >
{
public:
// This function controls the maximum amount of objects.
static void allow( std::size_t maxnum )
{
threading::Guard guard( lock_ );
LimitedType< CountedType >::maxObjects_ = maxnum ;
}
// propagate the count function into the public interface
using ObjectCounter< CountedType >::count;

protected:
LimitedType()
{
init();
}
LimitedType( const LimitedType& )
{
init();
}
~LimitedType()
{;}
private:
void init()
{
threading::Guard guard( lock_ );
if ( count() + 1 > maxObjects_ )
throw TooManyObjects( "Limit on number of objects
exceeded" );
}

static std::size_t maxObjects_;
static threading::CriticalSection lock_;
};

template < typename CountedType >
threading::CriticalSection LimitedType< CountedType >::lock_;
template < typename CountedType >
std::size_t LimitedType< CountedType >::maxObjects_ = 1;

} // end namespace utility
#endif // inclusion guard

main.cpp

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

using namespace std;


class MyClass : private utility::LimitedType< MyClass >
{
public:
using utility::LimitedType< MyClass >::allow;
using utility::LimitedType< MyClass >::count;
};

void exceptiontest()
{
try
{
MyClass array[3];
}
catch( utility::TooManyObjects& )
{
cout << "exception correctly caught" << endl;
}
}

int main()
{
exceptiontest();

return 0;
}

this gives:-
object counter with tests error LNK2001: unresolved external symbol
"private: static unsigned int utility::LimitedType<class
MyClass>::maxObjects_"
(?maxObjects_@?$LimitedType@VMyClass@@@utility@@0IA)
object counter with tests error LNK2001: unresolved external symbol
"private: static class threading::CriticalSection
utility::LimitedType<class MyClass>::lock_"
(?lock_@?$LimitedType@VMyClass@@@utility@@0VCriticalSection@threading@@A)
object counter with tests error LNK2001: unresolved external symbol
"private: static unsigned int utility::ObjectCounter<class
MyClass>::count_" (?count_@?$ObjectCounter@VMyClass@@@utility@@0IA)
object counter with tests error LNK2001: unresolved external symbol
"private: static class threading::CriticalSection
utility::ObjectCounter<class MyClass>::lock_"
(?lock_@?$ObjectCounter@VMyClass@@@utility@@0VCriticalSection@threading@@A)
object counter with tests fatal error LNK1120: 4 unresolved externals

What am I doing wrong? Am I missing something here or is my compiler
sucky?
 
J

John Harrison

Improving said:
msvc 7 here.
can you try these john. sorry for length.

Missing a file called object_counter.h.

Can't see anything obviously wrong.

john
 
J

John Harrison

Improving said:
its there, i mistook its name. its not counted_type.h its
object_counter.h

Well there seem to be a couple of typos, for instance

~ObjectCounter()
{
threading::Guard( lock_ );
--ObjectCounter< CountedType >::count_;
}

should be

~ObjectCounter()
{
threading::Guard guard( lock_ );
--ObjectCounter< CountedType >::count_;
}

similarly in one of the constructors.

With those fixed it compiles and links for me.

john
 
I

Improving

dammit i fixed those typos before then while playing with the code
reverted to an earlier version. doh. still fixed them again and still 4
unresolved externals. Oh how i wish I had 7.1. Im stuck with .net. Do
you know where there is a list of standard conformance issues for
msvc7. I'd like to know if this is a compiler problem. Thanks anyway. I
guess if msvc7.1 takes it the code must be fine. Any idea of the
workaround for msvc7? I think its pretty obvious from the code what I'm
trying to do.
 
J

John Harrison

Improving said:
dammit i fixed those typos before then while playing with the code
reverted to an earlier version. doh. still fixed them again and still 4
unresolved externals. Oh how i wish I had 7.1. Im stuck with .net. Do
you know where there is a list of standard conformance issues for
msvc7.

I have seen a list from the Deep C++ column

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndeepc/html/deep051099.asp

Not precisely sure which version of MSVC++ this applies to.

I'd like to know if this is a compiler problem. Thanks anyway. I
guess if msvc7.1 takes it the code must be fine. Any idea of the
workaround for msvc7? I think its pretty obvious from the code what I'm
trying to do.

You might try something like this

template < typename CountedType >
class ObjectCounter
{
public:
static std::size_t count()
{
threading::Guard guard( the_lock() );
return the_count();
}
protected:
ObjectCounter()
{
threading::Guard guard( the_lock() );
++the_count();
}
ObjectCounter( const ObjectCounter< CountedType >& )
{
threading::Guard guard( the_lock() );
++the_count();
}
~ObjectCounter()
{
threading::Guard guard( the_lock() );
--the_count();
}
private:
static std::size_t& the_count()
{
static std::size_t count = 0;
return count;
}
static threading::CriticalSection& the_lock()
{
static threading::CriticalSection lock;
return lock;
}
};

Not compiled, so apologies for any typos etc.

john
 
I

Improving

went right through those deep c++ articles. Didn't see anything
pertinent. The workround you suggested looks workable but i still
prefer my design. Oh well I've wanted 7.1 for a long time now i got an
excuse to go out and buy it. might even be able to get it cheap as 8
will be out soon.
 
I

Improving

Sorted it. Made a new project. then it compiled and linked. very
strange.
Thanks for your time john.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top