Re: limiting a template class to certain types ?
* Steve Hicks:
Michiel.Salters@tomtom.com wrote:
Just add a test, using the typedef T type; trick again.
template<bool b> struct 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 b> struct test;
template <> struct test<true> { };
template <class T, bool b>
struct test_identity : test<b> {
typedef T type;
};
template <class T> struct is_callable {
static const bool value = false;
};
template <class T> class Constant {
T value;
public:
Constant(T t) : value(t) { }
void operator()()
{ std::cout << "value: " << value << std::endl; }
};
template <class T> struct is_callable<Constant<T> > {
static const bool value = true;
};
// T1 and T2 must be callable
template <class T1, class T2> class 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,T2> if 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<int> a = 5; Constant<double> b = 10.3;
(a+b)();
works, but
Constant<int> a = 5;
(a+10.3)();
fails to compile, despite my implicit constructor, since it tries to
make Sum<Constant<int>,int> and in doing so, tries to make
test<is_callable<int>::value> which 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 T> class 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<T> const& x )
{ return static_cast<T>( x() ); } // Cast due to use of 'double'.
template <class T1, class T2> class 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,T2> operator+(T1 t1,T2 t2) { return Sum<T1,T2>(t1,t2); }
int main()
{
Constant<int> a = 5; Constant<double> b = 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?