template class members

Started by
5 comments, last by stylin 18 years, 7 months ago
Hi. I was wondering if somebody could help me with this bit of code.
template< unsigned int array_size = 3 >
class A {
	unsigned char array_[ array_size ];
	unsigned int array_size_;
public:
	A(): array_( new unsigned char[array_size] ), array_size_( array_size ) {};
};

class B {
	A<?> a_;
public:
	B( int arbitrary, int vars ) {};
};

I have a templated class A, that takes a non-type parameter for a simple array dimension. And I have a class B that needs to hold a certain class A based on unrelated values. How can I have a templated member when its type is unknown? I don't want class B parameterized, and I'd rather not have class A inherit from a base class, but these seem to be my only options. If anyone as any insight into this, I'd appreciate it greatly. Thanks.
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid
Advertisement
The declaration for A doesn't make much sense: you have a fixed-size array as a member, attempt to initialize it with a pointer to a dynamically allocated array, and store the size (which can't change) as yet another member.

But if I understand the situation correctly you have a set of types (class template A) and want to use instances of those types polymorphically (in B). That usually means inheritance in C++ (specifically a common base class for A).

Wouldn't you be better off using arrays of dynamic size in A (making it a regular class)? Is it critically important to keep the array size known at compile time?
Quote:Original post by spock
The declaration for A doesn't make much sense: you have a fixed-size array as a member, attempt to initialize it with a pointer to a dynamically allocated array, and store the size (which can't change) as yet another member.

The real constructor looks like this:
A(): array_size_( array_size ) {};


Quote:Wouldn't you be better off using arrays of dynamic size in A (making it a regular class)? Is it critically important to keep the array size known at compile time?

There will only be 4 different instance types of class A. I have a templated function in class B that's parameterized by A class type. This function can work with all instances of class A except for A< 3 >, which I have a specialization for:
template< class AType >void B::UseA( AType pixel );template<>void B::UseA< A< 3 > >( A< 3 > a );

B::UseA is involved in rather tight loops, so I didn't want to check A's size every time I called B::UseA, so instead I parameterized A and B and left the type checking to the compiler.

I would like to typedef A in B (or store an actual A, either one) so that I can create instances of A based on B's members.
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid
It seems like you want compile-time issue (template parameter) to be determined at run-time, which cannot be done. However, there may be ways around. I would however like to get a better understanding of what it is you're actually doing. In particular, how does B's member a_ relate to the A passed to B::UseA? You might be able to do what you want with a variant (i.e. boost::variant):
class B{		boost::variant< A< 1 >, A< 2 >, A< 3 >, A< 4 > > a_;	public:		B(int arbitrary, int vars)			:			a_((arbitrary < 3) ? ((arbitrary == 1) ? A< 1 >() : A< 2 >()) : ((arbitrary == 3) ? A< 3 >() : A< 4 >()))		{		}		template < unsigned int size >		void UseA(A< size > a)		{			boost::apply_visitor(someVisitor(a), a_);		}};

Enigma
Quote:Original post by Enigma
I would however like to get a better understanding of what it is you're actually doing. In particular, how does B's member a_ relate to the A passed to B::UseA?

I'm trying to write a small wrapper for SDL pixels and surfaces. I didn't like SDL's example implementation of PutPixel() checking for a 24-bit pixel depth every time it's called. For 8, 16 and 32 bit depths the addressing and casting are the same, so I parameterized a pixel struct to pass to it, and I parameterized PutPixel() so I could specialize the 24-bit pixel case. I also took the SDL_MapRGBA() call out of there.

However I'm still passing an SDL_Surface * to PutPixel(), and it's still the responsibility of the user (me) to create a correct pixel type for the surface format to pass to PutPixel(). So I was thinking of moving PutPixel() into a surface object, and having a current_value_ pixel type, so I could do this:
Surface surface( 640, 480, 32, SDL_SWSURFACE);...surface.SetPixelColor( 0x80, 0x10, 0x20, 0x00 );surface.PutPixel( 50, 40 );

Although it might be becoming too bloated for my own good. I'll look into boost::variant, thanks for the tip.

EDIT: I could have a regular Surface::PutPixel function which creates a Pixel< surface_->format->BytesPerPixel >, maps color to it using the values stored in Surface::SetPixelColor, and then calls a private parameterized Surface::PutPixel_ function. But if I do that, I might as well have Surface::PutPixel( x, y, r, g, b, a ). I want to be able to put consecutive pixels down without remapping colors every time.
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid
class A {  unsigned char* array_;  unsigned size_t array_size_;public:  A(int array_size = 3): array_( new unsigned char[array_size] ), array_size_( array_size ) {}// And since you'll need them...  A(const A& rhs) : array_( new unsigned char(other.array_size_)), array_size_(other.array_size) { std::copy(array_, array_ + array_size_, other.array_); }  A& operator=(const A& other) { A rhs(other); std::swap(array_, other.array_); array_size_ = rhs.array_size_; }  ~A() { delete[] array_; }// Finally, give read-only access to the size info.  size_t size() { return array_size_; }};// On the other hand, you COULD just use std::vector...class B {  A a_;public:  B( int arbitrary, int vars ) : a_(arbitrary);};template <typename T>void B::doSomethingWith(const T& var) {  // etc.}// specialize:template<>void B::doSomethingWith< A >( const A& a ) {  if (a.size() == 3) {    // do special case stuff here  } else {    // copy logic from base here.  }  // That's if I understand you correctly. If all you intend is that  // doSomethingWith() works with all sizes of A, then there's no need  // for templating at all; just check the size here.}
Thanks Zahlman, that was my first solution, before I got rid of the size check. Looks like I should go back to that then.
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid

This topic is closed to new replies.

Advertisement