NeomerArcana
NeomerArcana

Reputation: 2249

Template classes conversion between template types but also specialised

Basically I want to accomplish this Conversion between 2 template types

But I want the assignment operator or copy constructor to be specialised.

For example, I have a color class:

template<typename T = float>
class color
{
public:
    T r;
    T g;
    T b;
    T a;

    color(T R, T G, T B, T A)
    : r(R), g(G), b(B), a(A)
    {
    }
};

Generally, color components are needed as floats between 0 and 1. However, it's often easier to provide the components as numbers between 0 and 255 because that's generally what you get in Photoshop or GIMP.

So, I'd like instances of this class to be able to convert between a float and an int type:

color<int> c1(255,234,122,14);
color<float> c2 = c1;

And when it does this, the numbers in c1 are divided by 255 to get the 0 to 1 equivalent.

So I've done this so far:

template<typename U>
color<T>(color<U> c)
: r(c.r/255.0), g(c.g/255.0), b(c.b/255.0), a(c.a/255.0)
{
}

But this would also divide a float instance by 255 as well. I can't figure out how to specialise this constructor (or assignment operator) to only be valid for int to float specialisations.

Upvotes: 2

Views: 137

Answers (1)

tahsmith
tahsmith

Reputation: 1723

EDIT

Maybe this does solve your problem. You only want to fully specialise the constructor for the conversions color<int> -> color<float> and vice-versa. This is allowed.

#include <iostream>
using namespace std;

template<typename T>
class color
{
public:
    T r,g,b,a;

    color(T r, T g, T b, T a) : r(r), g(g), b(b), a(a) {}

    template<typename OtherT>
    color(const color<OtherT>&);
};

template<>
template<>
color<int>::color(const color<float>& other) : 
r(other.r * 255), 
g(other.g * 255), 
b(other.b * 255),
a(other.a * 255)
{}

int main() {

    color<float> c1 = { 1.0f, 1.0f, 1.0f, 1.0f };
    color<int> c2 = c1;

    cout << c2.r << " " << c2.g << " " << c2.b << " " << c2.a << endl;
    return 0;
}

My old answer I think I would prefer though, since this will give hard-to-interpret error if the user puts in a template parameter other than int or float. The other method is very explicit.

Old answer

The main problem with what you want is that you cannot partially specialise a single method in a class template.

If the only two parameters used for template class color are int and float, I would arrange it like this: Have a base template class that contains the common code, and two classes that derive from it and provide the specialised constructors.

template<typename T> class base_color { ... common code between int and float };

Then two classes that have specific conversion constructors

class int_color : public base_color<int>
{
public:
    int_color(const float_color&) { ... }
}

class float_color : public base_color<float>
{
public:
    float_color(const int_color&) { ... }
}

Upvotes: 2

Related Questions