Sign in to follow this  
tnutty

class template question

Recommended Posts

I assume you mean in C++.

If a type doesn't support an arithmetic operation and the container requires it, it won't compile. Explicitly restricting the types a container can operate on, beyond what is functionally required of them, would limit the flexibility of your continer, which could cause you grief later.

Edit: Just to clarify, when I say 'requires it', I mean they are used somewhere in the containers definition, not enforced by some arbitrary restriction.

[Edited by - Liam M on July 22, 2009 8:31:59 PM]

Share this post


Link to post
Share on other sites
Actually, come to think of it, you can do it using template specialisation, like so:


template <class T> class MyClass
{
public:

MyClass();
};



template <> MyClass<int>::MyClass()
{
//Constructor junk.
}

int main()

{
CTest<int> t; //this is OK, constructor is defined.
CTest<float> t; //This isn't, no constructor is defined for float.
return 0;
}



But once again, don't box yourself in needlessly.

Share this post


Link to post
Share on other sites
Yes its correct assumption, Hodgman. I just wan't to emulate the valarray class
but with custom functions for my needs. For those who don't know me yet, I use
C++.

Share this post


Link to post
Share on other sites
Quote:
Original post by Liam M
Actually, come to think of it, you can do it using template specialisation, like so:



template <class T> class MyClass
{
public:

MyClass();
};

template <> MyClass<int>::MyClass()

{
//Constructor junk.
}


int main()

{
CTest<int> t;
return 0;
}



Way to much work for me.

Share this post


Link to post
Share on other sites
I agree with Liam M that this is a bad idea - why do you need to restrict the set of template arguments?

However, here's another solution:
template<class T> struct IsNumber          { const static int value = 0; };
template<> struct IsNumber<int> { const static int value = 1; };
template<> struct IsNumber<unsigned int> { const static int value = 1; };
template<> struct IsNumber<short> { const static int value = 1; };
template<> struct IsNumber<unsigned short> { const static int value = 1; };
template<> struct IsNumber<float> { const static int value = 1; };
template<> struct IsNumber<double> { const static int value = 1; };
//add other allowed number types here...

template<class T>
class MyNumber
{
public:
MyNumber()
{
int assert_is_number[ IsNumber<T>::value ];(void)assert_is_number;
}
T number;
};

MyNumber<int> foo;//ok
MyNumber<char> bar;//compiler error

Share this post


Link to post
Share on other sites
Quote:
Original post by Hodgman
However, here's another solution:*** Source Snippet Removed ***

Or you could just is Boost.TypeTraits' is_arithmetic<>.

Share this post


Link to post
Share on other sites
SFINAE allows you to specify that a template will only be matched for specific types. Using this and type traits, we can construct a templated class that will only be matched for arithmetic types. This is somewhat easier than specializing on each type you wish to support (long, int, double, float, etc).


template <typename T, typename Enable = void>
class MyClass
{};

template <typename T>
class <T, typename boost::enable_if<boost::is_arithmetic<T> >::type>
{
// stuff
};




Note that boost is pretty much a prerequisite for easily doing this. More reading can be found on boost::enable_if.

Share this post


Link to post
Share on other sites
Just to clarify. I mean I just want to limit the class object to Integral
and compound datatypes. So no char, char * , string, string* and so on.
Although I am not saying that I don't want to use strings and chars inside the
class, say for something like a getError() function.

Share this post


Link to post
Share on other sites
Quote:
Original post by tnutty
Just to clarify. I mean I just want to limit the class object to Integral
and compound datatypes. So no char, char * , string, string* and so on.
Although I am not saying that I don't want to use strings and chars inside the
class, say for something like a getError() function.


Why do you want to restrict the data type in such a manner in the first place?

Share this post


Link to post
Share on other sites
I really don't want to use boost, even if its popular amongst you guys and maybe
some girls. I guess I could use specialization :(.


int assert_is_number[ IsNumber<T>::value ];
(void)assert_is_number;


Question:

Would that work if value is a float? What is (void)assert_is_number doing?

Share this post


Link to post
Share on other sites
Quote:
Original post by Liam M
Quote:
Original post by tnutty
Just to clarify. I mean I just want to limit the class object to Integral
and compound datatypes. So no char, char * , string, string* and so on.
Although I am not saying that I don't want to use strings and chars inside the
class, say for something like a getError() function.


Why do you want to restrict the data type in such a manner in the first place?


I want to make a class to specialize in working with just numbers.

Share this post


Link to post
Share on other sites
Quote:
Original post by tnutty

int assert_is_number[ IsNumber<T>::value ];
(void)assert_is_number;
Question:
Would that work if value is a float?
Yes that's what this line is for:
template<> struct IsNumber<float>          { const static int value = 1; };
Quote:
What is (void)assert_is_number doing?
The variable "assert_is_number" isn't actually used, it's just there to create a compiler error in cases where "IsNumber::value" isn't 1. Therefore the compiler might give you an "unused local variable" warning/error.

You can use this line of code to disable the warning:
(void)variableName;

Share this post


Link to post
Share on other sites
Liam M, I think I like your first suggestion. After looking at the valarray
class, I see that they do something similar. I will let the ctor check if
the dataType is valid with something like

NumArrayClass(const Type& val_, unsigned int size_);
{
Resize_(size_,val_);
}

so NumArrayClass<char> abcd('2',2) won't work without typeCast.

Share this post


Link to post
Share on other sites
Quote:
Original post by tnutty
I really don't want to use boost
Not wanting to point out the insanity of using C++ without Boost I'll just skip to suggesting that you can still implement your own code that borrows ideas taken from Boost:

template<class T>
struct disable_if_numeric { typedef void type; };

template<> struct disable_if_numeric<int>;
template<> struct disable_if_numeric<float>;
template<> struct disable_if_numeric<long>;
// etc

template <class T, class enable = void>
class foo
{
// todo
};

// prevent construction for non-numeric types
template <class T>
class foo<T, typename disable_if_numeric<T>::type> { private: foo(); };


int main()
{
foo<int> x; // works
foo<char*> y; // error : cannot access private member declared in class 'foo<T>'
}

Share this post


Link to post
Share on other sites
"Not wanting to point out the insanity of using C++ without Boost I'll just skip
to suggesting that you can still implement your own code that borrows ideas taken
from Boost:"

I am not saying I won't ever use it. All I am saying is that its really not
necessary right now for me.

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