views:

121

answers:

2

Suppose I represent an image class as:

template <typename Pixel> class Image { ... };

I would need my own swap function to prevent extra copying of images, so I would need to make it a friend of Image. If inside Image I write:

template <typename T> friend void swap(Image<T>&, Image<T>&);

I get what I want, but it makes all swap functions friends of all Image classes. So I can narrow the friend relationship as follows:

template <typename Pixel> class Image;
template <typename T> void swap(Image<T>&, Image<T>&);

template <typename Pixel> class Image {
   ...
   friend void swap<>(Image&, Image&);
};

as described in C++ FAQ-lite 35.16.

Now suppose I also have a convolution function that can take floating-point or integral kernels:

template <typename Pixel, typename KernelValue>
Image<Pixel> convolve(const Image<Pixel>&, const Kernel<KernelValue>&);

Convolution needs access to Image's raw memory, so it too must be a friend. However, I would like to partially narrow the friendship so that convolve is a friend for all KernelValues but only the particular Pixel type, something like:

template <typename KernelValue> friend Image<Pixel> 
    convolve(const Image<Pixel>&, const Kernel<KernelValue>&);

inside the Image definition. The compiler does not like this (or other variants) at all, mainly because it doesn't match the original function declaration, so the private pointer can't be accessed. Is it possible to get what I want here, or should I settle for the "more friendly" version?

+3  A: 

As far as I know you cannot have a partially specialized templated function.

You could make a Convolver struct that you can partially specialize and then create a wrapper to do the convolve.

+1  A: 

The only way I see this happening is defining the function inside the Image class, like so:

#include <iostream>
using std::cout;

template <typename Pixel>
struct image
{
    template <typename KernelValue>
    friend image<Pixel> convolve(image<Pixel> const&, image<KernelValue> const&)
    {
            cout << "foo\n";
            return image<Pixel>();
    }
};

int main()
{
    image<int> i;
    image<float> i2;

    convolve(i, i2);
}
Yuyo