C++ How do I cast from 1 template class to another? - c++

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?

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.

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; }

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.

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

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;
};

Related

Template function deduction fail on std::conditional argument

Please, before marking this as a duplicate of This question read the entirety of the post
This piece of code fails to compile, with a template deduction error:
#include <iostream>
#include <type_traits>
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
template<typename TYPE>
void Bar(MyType<TYPE> Input)
{
std::cout << typeid(Input).name() << std::endl;
}
};
int main()
{
MyClass<float, 1> c;
c.Foo();
return 0;
}
I understand the point that was made in the question i linked above, which is that "the condition which allows to choose the type to be deduced depends on the type itself", however, why would the compiler fail in the specific case i provided as the condition here seems to be fully independent from the type, or is there something i'm missing?
I would be more than happy if someone could refer to a section of the c++ standard that would allow me to fully understand this behaviour.
As the linked question, TYPE is non deducible. MyType<TYPE> is actually XXX<TYPE>::type.
You have several alternatives, from your code, I would say one of
Bar no longer template:
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
void Bar(MyType<T> Input)
{
std::cout << typeid(Input).name() << std::endl;
}
};
requires (or SFINAE/specialization for pre-c++20):
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
template<typename TYPE>
void Bar(TYPE Input) requires(N > 0)
{
std::cout << typeid(Input).name() << std::endl;
}
void Bar(double Input) requires(N <= 0)
{
std::cout << typeid(Input).name() << std::endl;
}
};

Enable Different Member Functions Depending On If Type Is POD

I believe this is fairly simply to achieve, but I can't figure out how.
Take the following example class:
class Example {
public:
template <typename T>
size_t foo(T& v) const;
};
How can I provide two implementations for this method depending on if T is a POD? I know there is an std::is_pod type trait, but I can't figure out how to have it enable the correct function.
I also need to be able to provide specific specializations for certain types of T regardless of if they are PODs or not. For example, I want to be able to write:
template <>
size_t foo<uint8_t>(uint8_t& b);
While all other types of T are chosen based upon being PODs or not.
EDIT
I have been looking at the information everyone has been giving and have come up with the following, however, this still does not work (throws a compiler error). I can't understand why.
class Example {
public:
template <typename T, bool U = std::is_trivially_copyable<T>::value>
size_t foo(T& v) const;
};
template <typename T>
size_t Example::foo<T, true>(T& v) const {
//Do something if T is mem copyable
}
template <typename T>
size_t Example::foo<T, false>(T& v) const {
//Do something if T is not mem copyable
}
Which results in "non-class, non-variable partial specialization 'foo<T, true>' is not allowed"
You can do it in the following way.
#include <iostream>
#include <type_traits>
struct A {
int m;
};
struct B {
int m1;
private:
int m2;
};
struct C {
virtual void foo() {};
};
// is_pod is deprecated since C++ 20
template <typename T>
std::enable_if_t<std::is_pod_v<T>, size_t> foo(const T& pod)
{
std::cout << &pod << " is_pod\n";
return 0;
}
template <>
size_t foo<uint8_t>(const uint8_t& b)
{
std::cout << int(b) << " is uint8_t\n";
return 1;
}
template <>
size_t foo<int>(const int& b)
{
std::cout << int(b) << " is int\n";
return 1;
}
int main()
{
uint8_t a = 2;
foo(a);
foo(22);
// will compile
A instance;
foo(instance);
// will not compile
B b;
//foo(b);
// will not compile
C c;
//foo(c);
}
output
2 is uint8_t
22 is int
010FFA64 is_pod
Here is what I did to get it to work correctly:
#include <type_traits>
#include <iostream>
class Example {
public:
Example(int a) : _a(a) {}
virtual void bar() {}
template <typename T, typename std::enable_if<std::is_trivially_copyable<T>::value, size_t>::type = 0>
size_t foo(T& v) const {
std::cout << "T is trivially copyable" << std::endl;
return sizeof(T);
}
template <typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, size_t>::type = 0>
size_t foo(T& v) const {
std::cout << "T is not trivially copyable" << std::endl;
return sizeof(T);
}
private:
int _a;
int _b;
int _c;
};
template <>
size_t Example::foo<unsigned int>(unsigned int& v) const {
std::cout << "T is unsigned int" << std::endl;
return sizeof(unsigned int);
}
int main() {
Example e(10);
int a;
e.foo(a);
char b;
e.foo(b);
e.foo(e);
unsigned int c;
e.foo(c);
return 0;
}
The output of which looks like:
T is trivially copyable
T is trivially copyable
T is not trivially copyable
T is unsigned int
This is based upon the following Provide/enable method to in a class based on the template type

How to specialise template method with type that itself is a template where only the return type relies on the template type?

I want to specialise a single template method in a non-template class to use an std::vector however only the return type of the method uses the template.
#include <iostream>
#include <string>
#include <vector>
class Foo
{
public:
template<typename T>
T Get()
{
std::cout << "generic" << std::endl;
return T();
}
};
template<>
int Foo::Get()
{
std::cout << "int" << std::endl;
return 12;
}
template<typename T>
std::vector<T> Foo::Get()
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
int main()
{
Foo foo;
auto s = foo.Get<std::string>();
auto i = foo.Get<int>();
}
This compiles with an error indicating that the std::vector attempted specialisation does not match any prototype of Foo, which is completely understandable.
In case it matters, use of C++14 is fine and dandy.
You can only partially specialize classes (structs) (cppreference) - so the way to overcome your problems is to add helper struct to allow this partial specialization of std::vector<T> - e.g. this way:
class Foo
{
private: // might be also protected or public, depending on your design
template<typename T>
struct GetImpl
{
T operator()()
{
std::cout << "generic" << std::endl;
return T();
}
};
public:
template<typename T>
auto Get()
{
return GetImpl<T>{}();
}
};
For int - you can fully specialize this function:
template<>
int Foo::GetImpl<int>::operator()()
{
std::cout << "int" << std::endl;
return 12;
}
For std::vector<T> you have to specialize entire struct:
template<typename T>
struct Foo::GetImpl<std::vector<T>>
{
std::vector<T> operator()()
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
};
Partial specialisation of template functions (including member functions) is not allowed. One option is to overload instead using SFINAE. For example,
/// auxiliary for is_std_vetor<> below
struct convertible_from_std::vector
{
template<typename T>
convertible_from_std::vector(std::vector<T> const&);
};
template<typename V>
using is_std_vector
= std::is_convertible<V,convertible_from_std_vector>;
class Foo
{
public:
template<typename T, std::enable_if_t< is_std::vector<T>::value,T>
Get()
{
std::cout << "vector" << std::endl;
return T();
}
template<typename T, std::enable_if_t<!is_std::vector<T>::value,T>
Get()
{
std::cout << "generic" << std::endl;
return T();
}
};
Note that the helper class is_std_vector may be useful in other contexts as well, so it worth having somewhere. Note further that you can make this helper class more versatile by asking for any std::vector or specific std::vector<specific_type, specific_allocator>. For example,
namespace traits {
struct Anytype {};
namespace details {
/// a class that is convertible form C<T,T>
/// if either T==AnyType, any type is possible
template<template<typename,typename> C, typename T1=Anytype,
typename T2=Anytype>
struct convCtTT
{
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C, typename T1=Anytype>
struct convCtTT<C,T1,AnyType>
{
template<typename T2>
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C, typename T2=Anytype>
struct convCtTT<C,AnyType,T2>
{
template<typename T1>
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C>
struct convCtTT<C,AnyType,AnyType>
{
template<typename T1, typename T2>
convCtTT(C<T1,T2> const&);
};
}
template<typename Vector, typename ValueType=AnyType,
typename Allocator=AnyType>
using is_std_vector
= std::is_convertible<Vector,details::convCtTT<std::vector,ValueType,
Allocator>;
}
You can't partially specialze template in c++. You need to overload your function and pass the type in parameters.
#include <iostream>
#include <string>
#include <vector>
class Foo
{
public:
template<typename T>
T Get()
{
return this->getTemplate(static_cast<T*>(0)); //
}
private:
template<class T> T getTemplate(T* t)
{
std::cout << "generic" << std::endl;
return T();
}
template<class T> std::vector<T> getTemplate(std::vector<T>* t)
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
};
template <> int Foo::getTemplate(int* t)
{
std::cout << "int" << std::endl;
return 12;
}
int main()
{
Foo foo;
auto s = foo.Get<std::string>();
auto i = foo.Get<int>();
auto v = foo.Get<std::vector<int>>();
}
Edit : fixed a typo in the code

Template specialization using another class that implicit-converts to it

I don't know if this is possible, but I would like to understand better how this works.
Can a class implict convertsion operation be used to match a template parameter?
This is what I want to do.
#include <iostream>
template<typename T>
struct Value {
};
template<>
struct Value<int> {
static void printValue(int v) {
std::cout << v << std::endl;
}
};
struct Class1 {
int value;
};
/*
template<>
struct Value<Class1*> {
static void printValue(Class1* v) {
std::cout << v->value << std::endl;
}
};
*/
template<typename X>
struct ClassContainer {
ClassContainer(X *c) : _c(c) {}
operator X*() { return _c; }
X *_c;
};
template<typename X>
struct Value<ClassContainer<X>> {
static void printValue(ClassContainer<X> v) {
std::cout << static_cast<X*>(v)->value << std::endl;
}
};
template<typename X>
void doPrintValue(X v)
{
Value<X>::printValue(v);
}
int main(int argc, char *argv[])
{
doPrintValue(10);
Class1 *c = new Class1{ 20 };
//doPrintValue(c); // error C2039: 'printValue': is not a member of 'Value<X>'
ClassContainer<Class1> cc(c);
doPrintValue(cc);
std::cout << "PRESS ANY KEY TO CONTINUE";
std::cin.ignore();
}
ClassContainer has an implict conversion to X*. Is it possible to match ClassContainer passing only X*?
If you want the template class for pointers to behave like the template class for something else, just inherit:
template<typename T>
struct Value<T*> : Value<ClassContainer<T>> {};
It will inherit the public printValue function, which accepts a parameter that can be constructed from T*, and everything will be implicitly converted as expected.
See it all live here.

Get type of implicit conversion

How can I get the return type of an implicit conversion of an object?
struct Bar {
operator int() const {
return 0;
}
};
// std::result_of<Bar>::type value; ???
// std::result_of<Bar::operator ??? >::type value;
I could use:
std::is_convertible<Bar, int>::value
but is_convertible is also true for float, unsigned int etc.... I would like to have the exact type.
Edit: Because my question seems unclear, why I want to know the implicit conversion type. Please think a step further to template classes. So i do not know Bar at all...
template<typename T, typename Sfinae = void>
struct ImplicitType
{
static_assert(sizeof(T) != sizeof(T), "Unknown type.");
};
template<typename T>
struct ImplicitType<T,
typename std::enable_if<std::is_convertible<T, int>::value && std::is_class<T>::value>::type>
{
using type = int;
};
template<typename T>
struct ImplicitType<T,
typename std::enable_if<std::is_convertible<T, float>::value && std::is_class<T>::value>::type>
{
using type = int;
};
struct Foo
operator float() const {
return 0.0f;
}
};
struct Bar {
operator int() const {
return 0;
}
};
ImplicitType<Foo> r; // <--- ambiguous template instantiation
ImplicitType<Bar> r; // <--- ambiguous template instantiation
For Foo I would like to get float. For Bar int.
But because I can define one or more implicit conversions for class, it gets tricky.
struct FooBar {
operator float() const {
return 0;
}
operator int() const {
return 0;
}
};
Not working live example.
So all in all it is not possible to get the right implicit conversation type of a class?
#include <iostream>
#include <typeinfo>
struct Bar {
operator int() const {
return 0;
}
operator double() const {
return 0.0;
}
struct Foo {
};
operator Foo() const {
return Foo();
}
};
int main() {
std::cout << typeid( decltype((int)Bar()) ).name();
std::cout << std::endl;
std::cout << typeid( decltype((double)Bar()) ).name();
std::cout << std::endl;
std::cout << typeid( decltype((Bar::Foo)Bar()) ).name();
std::cout << std::endl;
}
According to that fact, that function Bar::operator int() is a member function of class Bar, you guarantee, that there is a this reference for it, so that's why I provide a default object Bar() for all the stuff.
The result is:
i
d
N3Bar3FooE