473,323 Members | 1,574 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,323 software developers and data experts.

limiting a template class to certain types ?

Is it possible to limit a template class to certain types only. I found
a few things on the net but nothing seems to apply at compile time.

template <typename T>
class AClass
{
public:
AClass() {}
};

AClass<floatfloatSomethng; // yes it's fine
AClass<intintSomething; // no we don't want to allow the creation of
that object

Thank you, -mark

Jul 11 '06 #1
10 10152
ma*****@yahoo.com wrote:
Is it possible to limit a template class to certain types only. I found
a few things on the net but nothing seems to apply at compile time.

template <typename T>
class AClass
{
public:
AClass() {}
};

AClass<floatfloatSomethng; // yes it's fine
AClass<intintSomething; // no we don't want to allow the creation of
that object
template<typename T>
class AClass {
public:
AClass() { }
};

template<class AClass<int>;

int main()
{
AClass<doublead;
AClass<intai; // error
}

Jul 11 '06 #2
ma*****@yahoo.com wrote:
Is it possible to limit a template class to certain types only. I
found a few things on the net but nothing seems to apply at compile
time.

template <typename T>
class AClass
{
public:
AClass() {}
};

AClass<floatfloatSomethng; // yes it's fine
AClass<intintSomething; // no we don't want to allow the creation of
that object
The simplest way is probably hide the implementation of your template
type in a separate translation unit and use explicit instantiations
to stuff the same TU with the implementations of the class for some
specific types. A better way would be to design it so there is no
need to limit it.

Or you could do something like this (AKA "type traits"):

template<class Tclass allowed { enum { yes }; };

// then specialise it for the types that you allow:

template<class allowed<float{ public: enum { yes = 1 }; };
template<class allowed<double{ public: enum { yes = 1 }; };

// and last, use it:

template<typename T>
class AClass
{
static const bool allowed = allowed<T>::yes;

public:
AClass() {}
};

int main() {
AClass<floataf;
AClass<intaf; // error
}

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jul 11 '06 #3
ma*****@yahoo.com posted:

AClass<floatfloatSomethng; // yes it's fine
AClass<intintSomething; // no we don't want to allow the creation of

The examples on this page may interest you:

http://www.boost.org/doc/html/boost_staticassert.html

(However, one of the examples is dubious in that it should use
"numeric_limits<T>::digits" rather than "sizeof(T) * CHAR_BIT" ).

--

Frederick Gotham
Jul 11 '06 #4
Thanks everyone for your help !

Jul 12 '06 #5
Victor Bazarov wrote:
Or you could do something like this (AKA "type traits"):

template<class Tclass allowed { enum { yes }; };

// then specialise it for the types that you allow:

template<class allowed<float{ public: enum { yes = 1 }; };
template<class allowed<double{ public: enum { yes = 1 }; };

// and last, use it:

template<typename T>
class AClass
{
static const bool allowed = allowed<T>::yes;

public:
AClass() {}
};

int main() {
AClass<floataf;
AClass<intaf; // error
}
This works great for allowing certain templated classes to be used.
But what about functions and overloaded operators? For instance, if I
have a certain family of template classes, how could I overload an
operator so that it only acts on these classes? I'm thinking in
particular of boost::lambda, where they overload just about every
operator to work on the placeholders, but boost::spirit and many other
libraries do this sort of thing as well, even without the proposed
(TR2?) "concept" formalism.

To be more concrete. Suppose I have a predicate template of some sort,
either like your allowed<T>::yes enum, or maybe a bool
allowed_p<T>::value. Short of sticking all the allowed classes into an
unnamed namespace to restrict scope (since this allows classes from
global scope as well), how could I write this function

template<class T>
increment_return_type<T>::type operator++(T x);

so that T can ONLY be a class which satisfies the predicate?

Thanks,
steve hicks

Jul 12 '06 #6
Steve Hicks wrote:
[..] Suppose I have a predicate template of some
sort, either like your allowed<T>::yes enum, or maybe a bool
allowed_p<T>::value. Short of sticking all the allowed classes into
an unnamed namespace to restrict scope (since this allows classes from
global scope as well), how could I write this function

template<class T>
increment_return_type<T>::type operator++(T x);

so that T can ONLY be a class which satisfies the predicate?
I probably don't understand the requirements. Could you please provide
a C++ illustration (even if it doesn't compile)?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jul 12 '06 #7
To be more concrete. Suppose I have a predicate template of some sort,
either like your allowed<T>::yes enum, or maybe a bool
allowed_p<T>::value. Short of sticking all the allowed classes into an
unnamed namespace to restrict scope (since this allows classes from
global scope as well), how could I write this function

template<class T>
increment_return_type<T>::type operator++(T x);

so that T can ONLY be a class which satisfies the predicate?
Just add a test, using the typedef T type; trick again.

template<bool bstruct test; // undefined
template<struct test<true{ }; // defined specialization
template<typename T, bool b>
struct test_identity<T: test<b{
typedef T type;
};

template<class T>
increment_return_type<test_identity<T,
allowed_p<T>::value>::type>::type
operator++(T x);

HTH,
Michiel Salters

Jul 12 '06 #8
Mi*************@tomtom.com wrote:
Just add a test, using the typedef T type; trick again.

template<bool bstruct test; // undefined
template<struct test<true{ }; // defined specialization
template<typename T, bool b>
struct test_identity<T: test<b{
typedef T type;
};

template<class T>
increment_return_type<test_identity<T,
allowed_p<T>::value>::type>::type
operator++(T x);
That's a neat trick. Unfortunately, it doesn't quite do what I need.
Here is a small example:

/* BEGIN CODE */
#include <iostream>
template <bool bstruct test;
template <struct test<true{ };
template <class T, bool b>
struct test_identity : test<b{
typedef T type;
};
template <class Tstruct is_callable {
static const bool value = false;
};

template <class Tclass Constant {
T value;
public:
Constant(T t) : value(t) { }
void operator()()
{ std::cout << "value: " << value << std::endl; }
};
template <class Tstruct is_callable<Constant<T {
static const bool value = true;
};

// T1 and T2 must be callable
template <class T1, class T2class Sum {
T1 t1; T2 t2;
public:
Sum(T1 _t1, T2 _t2) : t1(_t1), t2(_t2) { }
void operator()() { t1(); t2(); }
};

template <class T1,class T2>
typename test_identity<Sum<T1,T2>,is_callable<T1>::value &&
is_callable<T2>::value>::type
operator+(T1 t1,T2 t2) {
return Sum<T1,T2>(t1,t2);
}
/* END CODE */

Basically, it only makes sense to have Sum<T1,T2if T1 and T2 are both
callable. I could easily insert a Boost static assert to ensure that
they are, but my issue is this: the overloaded operator+ still allows
any type to be sent to it, and then generates a compiler error if it's
not callable. So,

Constant<inta = 5; Constant<doubleb = 10.3;
(a+b)();

works, but

Constant<inta = 5;
(a+10.3)();

fails to compile, despite my implicit constructor, since it tries to
make Sum<Constant<int>,intand in doing so, tries to make
test<is_callable<int>::valuewhich is undefined.

I tried one more thing:

template <class T1,class T2>
Sum<T1,T2operator+(typename
test_identity<T1,is_callable<T1>::value>::type t1,
typename test_identity<T2,is_callable<T2>::value>::type t2) {
return Sum<T1,T2>(t1,t2);
}

but then my main() wouldn't compile because it couldn't implicitly
figure out that test_identity<T1,...>::type was really just T1.
Hopefully I've made my problem more clear. Thanks to those still
paying attention. Any ideas?

steve

Jul 13 '06 #9
* Steve Hicks:
Mi*************@tomtom.com wrote:
>Just add a test, using the typedef T type; trick again.

template<bool bstruct test; // undefined
template<struct test<true{ }; // defined specialization
template<typename T, bool b>
struct test_identity<T: test<b{
typedef T type;
};

template<class T>
increment_return_type<test_identity<T,
allowed_p<T>::value>::type>::type
operator++(T x);

That's a neat trick. Unfortunately, it doesn't quite do what I need.
Here is a small example:

/* BEGIN CODE */
#include <iostream>
template <bool bstruct test;
template <struct test<true{ };
template <class T, bool b>
struct test_identity : test<b{
typedef T type;
};
template <class Tstruct is_callable {
static const bool value = false;
};

template <class Tclass Constant {
T value;
public:
Constant(T t) : value(t) { }
void operator()()
{ std::cout << "value: " << value << std::endl; }
};
template <class Tstruct is_callable<Constant<T {
static const bool value = true;
};

// T1 and T2 must be callable
template <class T1, class T2class Sum {
T1 t1; T2 t2;
public:
Sum(T1 _t1, T2 _t2) : t1(_t1), t2(_t2) { }
void operator()() { t1(); t2(); }
};

template <class T1,class T2>
typename test_identity<Sum<T1,T2>,is_callable<T1>::value &&
is_callable<T2>::value>::type
operator+(T1 t1,T2 t2) {
return Sum<T1,T2>(t1,t2);
}
/* END CODE */

Basically, it only makes sense to have Sum<T1,T2if T1 and T2 are both
callable. I could easily insert a Boost static assert to ensure that
they are, but my issue is this: the overloaded operator+ still allows
any type to be sent to it, and then generates a compiler error if it's
not callable. So,

Constant<inta = 5; Constant<doubleb = 10.3;
(a+b)();

works, but

Constant<inta = 5;
(a+10.3)();

fails to compile, despite my implicit constructor, since it tries to
make Sum<Constant<int>,intand in doing so, tries to make
test<is_callable<int>::valuewhich is undefined.
You could try

template <class T1,class T2>
typename boost::enable_if_c<
is_callable<T1>::value && is_callable<T2>::value,
Sum<T1,T2>
>::type
operator+(T1 t1,T2 t2) { return Sum<T1,T2>(t1,t2); }

which I believe is specifically what you're asking for.

However, for your chosen problem this leads to a little (contained)
combinatorial explosion: it answers the question but does not solve the
problem in a reasonable way, and that's because you're not asking about
the problem but about a particular non-working way to solve it.

Better to simply make sure that anything that can behave as a constant
has a value:

#include <iostream>

template <class Tclass Constant {
T value;
public:
Constant(T t) : value(t) { }
double operator()() const
{ std::cout << "value: " << value << std::endl; return value; }
};

template< typename T T valueOf( T const& x )
{ return x; }
template< typename T T valueOf( Constant<Tconst& x )
{ return static_cast<T>( x() ); } // Cast due to use of 'double'.

template <class T1, class T2class Sum {
T1 t1; T2 t2;
public:
Sum(T1 _t1, T2 _t2) : t1(_t1), t2(_t2) { }
double operator()() const { return valueOf(t1) + valueOf(t2); }
};

template <class T1,class T2>
Sum<T1,T2operator+(T1 t1,T2 t2) { return Sum<T1,T2>(t1,t2); }

int main()
{
Constant<inta = 5; Constant<doubleb = 10.3;

std::cout << (a+b)() << std::endl;
std::cout << (a+10.3)() << std::endl;
}

Hth.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 13 '06 #10
Alf P. Steinbach wrote:
You could try

template <class T1,class T2>
typename boost::enable_if_c<
is_callable<T1>::value && is_callable<T2>::value,
Sum<T1,T2>
>::type
operator+(T1 t1,T2 t2) { return Sum<T1,T2>(t1,t2); }

which I believe is specifically what you're asking for.

However, for your chosen problem this leads to a little (contained)
combinatorial explosion: it answers the question but does not solve the
problem in a reasonable way, and that's because you're not asking about
the problem but about a particular non-working way to solve it.
That's a handy little tool. But you're right that it didn't quite
solve the problem. I still couldn't make the compiler figure out to do
the implicit cast.
Better to simply make sure that anything that can behave as a constant
has a value:
....
template< typename T T valueOf( T const& x )
{ return x; }
template< typename T T valueOf( Constant<Tconst& x )
{ return static_cast<T>( x() ); } // Cast due to use of 'double'.

template <class T1, class T2class Sum {
T1 t1; T2 t2;
public:
Sum(T1 _t1, T2 _t2) : t1(_t1), t2(_t2) { }
double operator()() const { return valueOf(t1) + valueOf(t2); }
};

template <class T1,class T2>
Sum<T1,T2operator+(T1 t1,T2 t2) { return Sum<T1,T2>(t1,t2); }
Well, I'm not quite sure what you're doing there with the static_cast.
But I did realize I was going about it all wrong. My solution is to
define

template <class T,bool b=is_callable<T>::valuestruct callable_cast {
typedef Constant<Ttype;
};
template <class Tstruct callable_cast<T,true{
typedef T type;
};

Then, I can write (using a helper to maybe improve readability)

template <class T1,class T2struct sum_result {
typedef Sum<typename callable_cast<T1>::type,
typename callable_cast<T2>::typetype;
};
template <class T1,class T2typename sum_result<T1,T2>::type
operator+(T1 t1,T2 t2) {
return typename sum_result<T1,T2>::type(t1,t2);
}

This way, the overloaded operator can take whatever it wants, and the
cast becomes explicit. My interest in this problem came from trying to
make a toy version of boost::lambda to see how it worked (cf. a post
from 4-5 days earlier), and realizing that I needed to enclose all my
literals in "make_constant(...)" so that they would cooperate with my
operators since they could only act on placeholder expressions. This
should solve that particular problem (now I just need to figure out how
to get the reference- and const-casting to work...)

Thank you all very much!
steve

Jul 13 '06 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Kartsev | last post by:
hello! how to limit class template parameter T in template <class T> SomeClass { /*.... */ }
8
by: Thomas Heller | last post by:
I need to convert C preprocessor definitions into python code. The definitions are dumped out of gccxml (see http://www.gccxml.org) , running over the windows header files (for example). This...
3
by: case2005 | last post by:
Can anyone help with the following, I don't know if it's possible, but I'm certain there must be a standard way of dealing with this. I have the following: template<typename FooBar, typename...
9
by: Ann Huxtable | last post by:
I have the following code segment - which compiles fine. I'm just worried I may get run time probs - because it looks like the functions are being overloaded by the return types?. Is this Ok: ? ...
3
by: Alfonso Morra | last post by:
if I have a base class A declared as: template <typename T1, typename T2, my_enum_1=NONE, my_enum_2=ALL, bool=true> class A { .... };
12
by: mlimber | last post by:
This is a repost (with slight modifications) from comp.lang.c++.moderated in an effort to get some response. I am using Loki's Factory as presented in _Modern C++ Design_ for message passing in...
19
by: n.torrey.pines | last post by:
I have the following tree definition: template<typename T> struct tree { T first; vector<tree<T second; // branches }; which compiles successfully. What I'd like to do though is to use...
32
by: Stephen Horne | last post by:
I've been using Visual C++ 2003 for some time, and recently started working on making my code compile in GCC and MinGW. I hit on lots of unexpected problems which boil down to the same template...
9
by: Marco Nef | last post by:
Hi there I'm looking for a template class that converts the template argument to a string, so something like the following should work: Convert<float>::Get() == "float"; Convert<3>::Get() ==...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.