Reputation: 16705
I have a class which I intend to use with either the type float
or double
. As far as I am aware, there is no way to restrict template options, so perhaps I might be doing something dangerous here?
template<class T>
class A
{
A(T arg) { _data = arg; }
T _data;
}
typedef A<float> A_f;
typedef A<double> A_d;
How can I do the following?
int main()
{
A_f f(3.1415);
A_d d(3.1415);
f = (A_f)d;
}
IE: Cast the class containing data of type double to the class containing data of type float.
Edit: This doesn't seem to be going anywhere, so I tried playing around with this, but obviously I have no idea what to do here so it doesn't compile...
template<class T>
class A
{
friend // Intention is for T to be double here
A<float> operator A<float>(const A<T> input);
}
A<float> operator A<float>(const A<double> input)
{
return A<float>(input._data);
}
Maybe this helps explain what I want to achieve?
Second Edit for Adam:
return A<float>((float)input._data);
Is this better?
Upvotes: 1
Views: 7062
Reputation: 49986
Example with template conversion operator + static_assert for type verify:
http://coliru.stacked-crooked.com/a/6b01010ea5f02aee
#include <vector>
#include <iostream>
template < typename T > class TD; // type visualiser
template<class T>
class A
{
public:
A(T arg) { _data = arg; }
template<typename D>
operator A<D>() {
static_assert(std::is_same<D, float>::value || std::is_same<D, double>::value, "double/floats allowed only");
//TD<D>(); // D is float here
return static_cast<D>(_data);
}
T _data;
};
typedef A<float> A_f;
typedef A<double> A_d;
typedef A<int> A_i;
int main() {
A_f f(3.14151);
A_d d(3.14152);
std::cout << f._data << std::endl;
std::cout << d._data << std::endl;
f = (A_f)d;
//f = (A_i)d; // static assertion here
std::cout << f._data << std::endl;
return 0;
}
[edit]
template<class T>
class A
{
public:
A(T arg) { _data = arg; }
template<typename D>
operator A<D>() {
static_assert(std::is_same<D, float>::value || std::is_same<D, double>::value, "double/floats allowed only");
//TD<D>(); // D is float here
return A<D>(static_cast<D>(_data));
}
T _data;
};
Upvotes: 0
Reputation: 17329
I'll second the arguments that you should not cast like that, but if you insist, add a templated copy constructor:
template<class T>
class A
{
public: // add this
A(T arg) { _data = arg; }
template <class U> // add this
A(A<U> arg) { _data = arg._data; } // add this
T _data;
}
This will then allow conversions from A<U>
to A<T>
as long as U
is implicitly convertible to T
.
Upvotes: 1
Reputation:
There is an option to customize a class based on the type you provide it. The technique is called 'template specialization'
#include <iostream>
using namespace std;
template <typename T>
class A {
public:
void print_my_type() {
cout << "Generic template instance" << endl;
}
explicit operator A<int>() const {
cout << "Casting to int" << endl;
return A<int>();
}
};
template <>
class A<int> {
public:
void print_my_type() {
cout << "Class templated with an int" << endl;
}
explicit operator A<double>() const {
cout << "Casting to double" << endl;
return A<double>();
}
};
int main() {
A<double> a;
A<int> b;
a.print_my_type();
b.print_my_type();
a = static_cast<A<double>>(b);
return 0;
}
You should not cast objects like that. If you intend to have an object that you want to cast to another. You should provide it an operator A()
method so it can handle conversions gracefully
Upvotes: 0
Reputation: 7320
You could use std::enable_if
to only allow certain types :
#include <type_traits>
using namespace std;
// Our catch-all is not defined, so will not compile
// Could also be made to print a nice error message
template<typename T, typename Sfinae = void> class A;
// Ok if T is float or double
template<typename T>
class A<T, typename std::enable_if<std::is_same<T, float>::value
|| std::is_same<T, double>::value>::type>
{
// Your class here
};
int main()
{
A<int> a; // FAILS
A<float> b; // Ok
A<double> c; // Ok
return 0;
}
Then you just need to define a conversion operator in your class for the cast to work.
Upvotes: 3
Reputation:
Do not cast, but provide one (and only one) implicit conversion constructor or conversion operator. In your case it might be as trivial as operator T () const { return _data; }
Upvotes: 1