Partial Specialization Method

M

MathStuf

I have a matrix class and I would like to add a method that is only
applicable when the template type is a of another class. How can I
specialize the class to allow for the new method and hide it with any
other type?

template<class T> class Matrix
{
public:
Matrix();
Matrix(Ini
&ini); // Only
applicable with MyClass
Matrix(unsigned w, unsigned h, T &d = T());

void ImportIni(Ini
&ini); // Only applicable
with MyClass
void ExportIni(std::eek:fstream &fout, const String &val);// Only
applicable with MyClass

void AddRow(T &d = T());
void AddCol(T &d = T());
bool InsertRow(unsigned pos, T &d = T());
bool InsertCol(unsigned pos, T &d = T());
bool DeleteRow(unsigned pos);
bool DeleteCol(unsigned pos);

bool Set(unsigned row, unsigned col, T &s);

T Get(unsigned row, unsigned col);
std::vector<T> GetRow(unsigned row);
std::vector<T> GetCol(unsigned col);
unsigned GetHeight();
unsigned GetWidth();

T operator[](Point &p);
std::vector<T> operator[](int col);
private:
std::vector< std::vector<T> > matrix;
unsigned height;
unsigned width;
};
 
M

Markus Schoder

I have a matrix class and I would like to add a method that is only
applicable when the template type is a of another class. How can I
specialize the class to allow for the new method and hide it with any
other type?

template<class T> class Matrix
{
public:
Matrix();
Matrix(Ini
&ini); // Only
applicable with MyClass
Matrix(unsigned w, unsigned h, T &d = T());

It is illegal to bind a rvalue to a non-const reference. Make this a
const T & if possible.
void ImportIni(Ini
&ini); // Only applicable
with MyClass
void ExportIni(std::eek:fstream &fout, const String &val);// Only
applicable with MyClass

void AddRow(T &d = T());
void AddCol(T &d = T());
bool InsertRow(unsigned pos, T &d = T()); bool InsertCol(unsigned
pos, T &d = T()); bool DeleteRow(unsigned pos);
bool DeleteCol(unsigned pos);

bool Set(unsigned row, unsigned col, T &s);

T Get(unsigned row, unsigned col);
std::vector<T> GetRow(unsigned row);
std::vector<T> GetCol(unsigned col);
unsigned GetHeight();
unsigned GetWidth();

T operator[](Point &p);
std::vector<T> operator[](int col);
private:
std::vector< std::vector<T> > matrix; unsigned height;
unsigned width;
};

You can do it with template specialization, like so:

template<class T> struct Base
{
// all common stuff from above
// ...
};

template<class T> struct Matrix : Base<T>
{
Matrix();
Matrix(unsigned w, unsigned h);
};

class MyClass;
class Ini;

template<> struct Matrix<MyClass> : Base<MyClass>
{
Matrix();
Matrix(unsigned w, unsigned h);

// additional stuff
Matrix(Ini &ini);
// ...
};


There is some unavoidable duplication for the constructors unfortunately.
 
M

MathStuf

I have a matrix class and I would like to add a method that is only
applicable when the template type is a of another class. How can I
specialize the class to allow for the new method and hide it with any
other type?
template<class T> class Matrix
{
public:
Matrix();
Matrix(Ini
&ini); // Only
applicable with MyClass
Matrix(unsigned w, unsigned h, T &d = T());

It is illegal to bind a rvalue to a non-const reference. Make this a
const T & if possible.


void ImportIni(Ini
&ini); // Only applicable
with MyClass
void ExportIni(std::eek:fstream &fout, const String &val);// Only
applicable with MyClass
void AddRow(T &d = T());
void AddCol(T &d = T());
bool InsertRow(unsigned pos, T &d = T()); bool InsertCol(unsigned
pos, T &d = T()); bool DeleteRow(unsigned pos);
bool DeleteCol(unsigned pos);
bool Set(unsigned row, unsigned col, T &s);
T Get(unsigned row, unsigned col);
std::vector<T> GetRow(unsigned row);
std::vector<T> GetCol(unsigned col);
unsigned GetHeight();
unsigned GetWidth();
T operator[](Point &p);
std::vector<T> operator[](int col);
private:
std::vector< std::vector<T> > matrix; unsigned height;
unsigned width;
};

You can do it with template specialization, like so:

template<class T> struct Base
{
// all common stuff from above
// ...

};

template<class T> struct Matrix : Base<T>
{
Matrix();
Matrix(unsigned w, unsigned h);

};

class MyClass;
class Ini;

template<> struct Matrix<MyClass> : Base<MyClass>
{
Matrix();
Matrix(unsigned w, unsigned h);

// additional stuff
Matrix(Ini &ini);
// ...

};

There is some unavoidable duplication for the constructors unfortunately.

Would it just be easier to make methods that throw() for the other
types then?

--MathStuf
 
M

Markus Schoder

I have a matrix class and I would like to add a method that is only
applicable when the template type is a of another class. How can I
specialize the class to allow for the new method and hide it with any
other type?
template<class T> class Matrix
{
public:
Matrix();
Matrix(Ini
&ini); // Only
applicable with MyClass
Matrix(unsigned w, unsigned h, T &d = T());

It is illegal to bind a rvalue to a non-const reference. Make this a
const T & if possible.


void ImportIni(Ini
&ini); // Only applicable
with MyClass
void ExportIni(std::eek:fstream &fout, const String &val);// Only
applicable with MyClass
void AddRow(T &d = T());
void AddCol(T &d = T());
bool InsertRow(unsigned pos, T &d = T()); bool
InsertCol(unsigned pos, T &d = T()); bool DeleteRow(unsigned
pos); bool DeleteCol(unsigned pos);
bool Set(unsigned row, unsigned col, T &s);
T Get(unsigned row, unsigned col);
std::vector<T> GetRow(unsigned row);
std::vector<T> GetCol(unsigned col);
unsigned GetHeight();
unsigned GetWidth();
T operator[](Point &p);
std::vector<T> operator[](int col);
private:
std::vector< std::vector<T> > matrix; unsigned height; unsigned
width;
};

You can do it with template specialization, like so:

template<class T> struct Base
{
// all common stuff from above
// ...

};

template<class T> struct Matrix : Base<T> {
Matrix();
Matrix(unsigned w, unsigned h);

};

class MyClass;
class Ini;

template<> struct Matrix<MyClass> : Base<MyClass> {
Matrix();
Matrix(unsigned w, unsigned h);

// additional stuff
Matrix(Ini &ini);
// ...

};

There is some unavoidable duplication for the constructors
unfortunately.

Would it just be easier to make methods that throw() for the other types
then?

Yes probably, but I would rather not implement these methods for the
other types at all or even better use a compile time assertion. That way
the linker resp. compiler will tell you if someone tries to use these
methods with the wrong class.
 
S

Sylvester Hesp

MathStuf said:
I have a matrix class and I would like to add a method that is only
applicable when the template type is a of another class. How can I
specialize the class to allow for the new method and hide it with any
other type?

template<class T> class Matrix
{
public:
Matrix();
Matrix(Ini
&ini); // Only
applicable with MyClass
Matrix(unsigned w, unsigned h, T &d = T());

void ImportIni(Ini
&ini); // Only applicable
with MyClass
void ExportIni(std::eek:fstream &fout, const String &val);// Only
applicable with MyClass

void AddRow(T &d = T());
void AddCol(T &d = T());
bool InsertRow(unsigned pos, T &d = T());
bool InsertCol(unsigned pos, T &d = T());
bool DeleteRow(unsigned pos);
bool DeleteCol(unsigned pos);

bool Set(unsigned row, unsigned col, T &s);

T Get(unsigned row, unsigned col);
std::vector<T> GetRow(unsigned row);
std::vector<T> GetCol(unsigned col);
unsigned GetHeight();
unsigned GetWidth();

T operator[](Point &p);
std::vector<T> operator[](int col);
private:
std::vector< std::vector<T> > matrix;
unsigned height;
unsigned width;
};

You can use SFINAE

template<class T> class Matrix
{
public:
/* ... */
template<class U>
Matrix(U yourIntParam,
typename enable_if_c<
is_same<T,MyClass>::value &&
is_convertible<U,int>::value
, int>::type = 0);
};

Now that constructor will only be considered by the compiler if T is MyClass
(and if the passed U is convertible to int, which, alas, is the downside for
making the constructor itself a template, as that is needed for SFINAE to be
able to work). Definitions of enable_if_c<>, is_same<> and is_convertible<>
can be found in boost, but I'll provide them here for completeness' sake.

template<bool B, class T> struct enable_if_c { };
template<class T> struct enable_if_c<true, T> { typedef T type; };

template<class T, class U> struct is_same { static const bool value =
false; };
template<class T> struct is_same<T,T> { static const bool value = true; };

template<class T, class U> struct is_convertible
{
private:
struct small { char c; };
struct large { char c[2]; };
static small foo(const U & u);
static large foo(...);
public:
static const bool value = (sizeof(foo(*(T*)1)) == sizeof(small));
};

- Sylvester Hesp
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top