F
Frank Neuhaus
Hi,
I am writing some template class to hold images. The template parameter is
simply the type of the pixels. I want the same class to also be able to
refer to sub-images of other Images (without refcounting or anything like
that - i.e. using the subimage is only allowed while the original image is
still alive).
While my copy constructor performs a deep-copy of the image, I added the
following constructor for sub-images:
Image(Image<T>& img, int left, int top, int width, int height);
Now say I have an image 'im' I can for example create another image that
refers to this image as follows:
Image<unsigned char> subim(im,10,10,50,50);
The problem is the following:
Assume 'im' is a const Image<unsigned char>. My constructor can no longer be
called since it doesn't accept a const Image. However I can not add the
const either, because someone could then modify the resulting subimage. So
what is actually needed is something that only allows the constructor to be
called for const Images, if the first parameter is a const Image... i.e
const Image<unsigned char> subim(im,10,10,50,50); // Ok
Image<unsigned char> subim(im,10,10,50,50); // Error, 'subim' not const
AFAIK, there is no way to achieve the above. Or is there?
My Ideas on the problem so far:
a)
Say I wrote a member function that returned the subimage as a const
Image<unsigned char>.
Can I assume that
const Image<unsigned char> subim=im.getSubimage(10,10,50,50);
_never_ calls the copy-constructor or the = operator of the Image (remember
that would trigger an expensive deep copy due to my copy-constructor and
=operator implementation) ?
It will _definitely_ call the copy-constructor though, if subim is not const
right?
b)
What I am currently doing to achieve the desired behavior is a bit of
template trickery:
I added two typedefs:
template<typename T>
class Image
{
public:
typedef typename boost::add_const<T>::type const_pixeltype;
typedef typename boost::remove_const<T>::type nonconst_pixeltype;
[...]
};
const_pixeltype represents T with const, so if T="unsigned
char"->const_pixeltype="const unsigned char"
nonconst_pixeltype represents T without const, so if T="const unsigned
char"->nonconst_pixeltype="unsigned char"
Now I overloaded the existing constructor with this:
Image(const Image<nonconst_pixeltype>& img, int left, int top, int width,
int height);
internally, this constructor makes sure (using a boost static assertion)
that you can only call it when T==const_pixeltype:
So
Image<const unsigned char> subim(im,10,10,50,50); // ok
but
Image<unsigned char> subim(im,10,10,50,50); // boost static assert!
Now since Image<const unsigned char> should be semantically equivalent, I
created an 'evil' conversion:
operator const Image<nonconst_pixeltype>&() const
{
return *(const Image<nonconst_pixeltype>*)this;
}
This allows an Image<const unsigned char> to be used as a const
Image<unsigned char>.
Though it works, I consider this solution as not very 'clean'. It is also a
bit confusing to use for people.
What do you think of this solution? Is there any nice(r) way to achieve what
I want? Or is it probably better to say - sorry - no support for subimages
of const images?
Thanks alot
Frank
I am writing some template class to hold images. The template parameter is
simply the type of the pixels. I want the same class to also be able to
refer to sub-images of other Images (without refcounting or anything like
that - i.e. using the subimage is only allowed while the original image is
still alive).
While my copy constructor performs a deep-copy of the image, I added the
following constructor for sub-images:
Image(Image<T>& img, int left, int top, int width, int height);
Now say I have an image 'im' I can for example create another image that
refers to this image as follows:
Image<unsigned char> subim(im,10,10,50,50);
The problem is the following:
Assume 'im' is a const Image<unsigned char>. My constructor can no longer be
called since it doesn't accept a const Image. However I can not add the
const either, because someone could then modify the resulting subimage. So
what is actually needed is something that only allows the constructor to be
called for const Images, if the first parameter is a const Image... i.e
const Image<unsigned char> subim(im,10,10,50,50); // Ok
Image<unsigned char> subim(im,10,10,50,50); // Error, 'subim' not const
AFAIK, there is no way to achieve the above. Or is there?
My Ideas on the problem so far:
a)
Say I wrote a member function that returned the subimage as a const
Image<unsigned char>.
Can I assume that
const Image<unsigned char> subim=im.getSubimage(10,10,50,50);
_never_ calls the copy-constructor or the = operator of the Image (remember
that would trigger an expensive deep copy due to my copy-constructor and
=operator implementation) ?
It will _definitely_ call the copy-constructor though, if subim is not const
right?
b)
What I am currently doing to achieve the desired behavior is a bit of
template trickery:
I added two typedefs:
template<typename T>
class Image
{
public:
typedef typename boost::add_const<T>::type const_pixeltype;
typedef typename boost::remove_const<T>::type nonconst_pixeltype;
[...]
};
const_pixeltype represents T with const, so if T="unsigned
char"->const_pixeltype="const unsigned char"
nonconst_pixeltype represents T without const, so if T="const unsigned
char"->nonconst_pixeltype="unsigned char"
Now I overloaded the existing constructor with this:
Image(const Image<nonconst_pixeltype>& img, int left, int top, int width,
int height);
internally, this constructor makes sure (using a boost static assertion)
that you can only call it when T==const_pixeltype:
So
Image<const unsigned char> subim(im,10,10,50,50); // ok
but
Image<unsigned char> subim(im,10,10,50,50); // boost static assert!
Now since Image<const unsigned char> should be semantically equivalent, I
created an 'evil' conversion:
operator const Image<nonconst_pixeltype>&() const
{
return *(const Image<nonconst_pixeltype>*)this;
}
This allows an Image<const unsigned char> to be used as a const
Image<unsigned char>.
Though it works, I consider this solution as not very 'clean'. It is also a
bit confusing to use for people.
What do you think of this solution? Is there any nice(r) way to achieve what
I want? Or is it probably better to say - sorry - no support for subimages
of const images?
Thanks alot
Frank