Sign in to follow this  
stylin

template class members

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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.
}

Share this post


Link to post
Share on other sites
Thanks Zahlman, that was my first solution, before I got rid of the size check. Looks like I should go back to that then.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this