C++ converting templates with operator overload - c++

I have a template class where I try to convert a template verision to another via operator overload
enum MyTypes {A,B,C}
template<MyTypes T>
MyClass {
const static MyType type_ = T;
template<MyTypes U>
MyClass<U> convert(MyTypes t) {
MyType<U> ret = MyType<U>();
....
return r;
}
template<MyTypes U>
MyClass<U> operator()() {
return convert(U);
}
}
However, this yields (on gcc, c11)
conversion from MyClass<0u> to non-scalar type MyClass<1u> requested
removing the template functions and trying
MyClass<A> operator()() {
MyClass<A> a = MyClass<A>();
...
return a;
}
throws
the error operator cannot be overloaded
Basically, what I am trying to achieve is that if I have
MyClass<A> a = MyClass<A>;
MyClass<B> b = a;
that it creates a new MyClass based on a and the conversion. Any idea what my mistake here is?
EDIT:
I tossed out one template function, just leaving the operator
template<MyTypes U>
MyClass<U> operator()() {
MyClass<U> ret = MyClass<U>();
...
return ret;
}
but this still yields
conversion from MyClass<0u> to non-scalar type MyClass<1u> requested
when trying to do
MyClass<B> = a

The following converts the value and allows for the assignment:
#include <iostream>
#include <string>
enum MyTypes { A, B, C };
template<MyTypes T>
struct MyClass{
const static MyTypes type_ = T;
std::string history{"started as " + std::to_string(T)};
template<MyTypes U>
operator MyClass<U> () {
return {history+" then became " + std::to_string(U)};
}
};
int main()
{
MyClass<A> a;
MyClass<B> b = a;
MyClass<C> c = b;
std::cout << a.history << '\n';
std::cout << b.history << '\n';
std::cout << c.history << '\n';
}
Output:
started as 0
started as 0 then became 1
started as 0 then became 1 then became 2

Related

Is there way out of this ambiguity?

Consider this (rather) simple example:
#include <iostream>
struct Out {
int value;
};
template<class Sink> decltype(auto) operator<<(Sink &&s, Out const &out) {
return out.value > 0? s << out.value : s;
}
struct In {
std::ostream &sink;
template<typename T> In &operator<<(T const &t) {
return sink << t, *this;
}
};
int main() {
In in{std::cout};
in << (1 << Out{3}) << '\n'; // Ok
in << Out{42} << '\n';
// error: use of overloaded operator '<<' is ambiguous
// (with operand types 'In' and 'Out')
}
Can such an ambiguity be addressed? We have two classes, each one defines such an operator overload to forward it to its internal type (classes are designed independently by two different people, and another person tries to use them in the same application.) I don't see a way this could be reformulated in terms of other operators, say, it's no use here to give up on A's friend operator<< and try to convert A to int; and to use some kind of complicated SFINAE to rule out some overloads still doesn't look helpful.
You might create additional overloads which would be the better match:
decltype(auto) operator<<(In& in, Out const &out) {
return in.operator<<(out);
}
decltype(auto) operator<<(In&& in, Out const &out) {
return in.operator<<(out);
}
Some semi-oldschool SFINAE seemingly does the trick, in the sense that it is now accepted by both gcc and clang (and they both print "8" and "42" equally):
#include <iostream>
#include <utility>
template<typename S, typename T> class can_shl {
using Left = char;
struct Right { char c[2]; };
template<typename U> static constexpr decltype(
std::declval<S>() << std::declval<U>(), Left{})
has_it(U &&);
static constexpr Right has_it(...);
public:
static constexpr bool value = sizeof(has_it(std::declval<T>())) == 1;
};
struct Out {
int value;
};
template<class Sink> auto operator<<(Sink &&s, Out const &out)
-> std::enable_if_t<!can_shl<Sink, Out>::value, decltype(out.value > 0? s << out.value : s)>
{
return out.value > 0? s << out.value : s;
}
struct In {
std::ostream &sink;
template<typename T> In &operator<<(T const &t) {
return sink << t, *this;
}
};
int main() {
In in{std::cout};
in << (1 << Out{3}) << '\n'; // Ok
in << Out{42} << '\n';
}
Personally I don't feel quite confident with that "only allow this in case it does not compile on its own" approach (is this perchance a (static) UB? what would I say if I were a C++ standard?)

Template specialization for derived classes with a common base

I want to make template specializations for classes with unknown name, I only know their base, and i want all derived classes to fall onto the specialized template functions.
The following code is a working one for Case 1-4. I couldn't make Case 5 to work.
Also this is mostly runtime checking with the is_base_of, a much more effective one would be a compile time solution, but i failed at that. :(
#include <typeinfo>
#include <iostream>
struct MyClass {};
struct Rnd : public MyClass {};
void* JustAVoidPointer=new int;
void* AnOtherPointer = new int;
struct A
{
template <typename T> operator T() const {
if (std::is_base_of<MyClass, T>::value == true)
{
JustAVoidPointer = (MyClass*)(new T);
std::cout << "Case 3"; return *((T*)(JustAVoidPointer));
}
std::cout << "Case 1"; return *((T*)AnOtherPointer);
}
//template <typename T> operator T&() {
// std::cout << "Case 5"; return *(this->operator T* ());
//}
template <typename T> operator T*() const {
if (std::is_base_of<MyClass, T>::value == true)
{
JustAVoidPointer = (MyClass*) new T;
std::cout << "Case 4"; return (T*)(JustAVoidPointer);
}
std::cout << "Case 2"; return *((T**)AnOtherPointer);
}
}a;
void main()
{
auto CantUseTheStructsName = [&]() {
struct Rnd : public MyClass {};
int z = a; //Case 1
int* w = a; //Case 2
Rnd x = a; //Case 3
Rnd* y = a; //Case 4
//Rnd& z=a; //Case 5
char* xx=0; std::cin >> xx;
}; CantUseTheStructsName();
}
I would appreciate any help or advice what you could give me, Thank you!:)
I have a feeling that it's impossible to differentiate between a reference operator template and a non reference one, the reference one always takes precedence if we provide both.
A workaround, and a compile time solution:
#include <typeinfo>
#include <iostream>
struct MyClass {};
struct Rnd : public MyClass {};
void* JustAVoidPointer=0;
void* AnOtherPointer = new int;
struct A
{
template <typename T, typename F = T*> operator T&() const {
return *((T*)CheckType(F{}, std::is_pointer<T>{}, std::is_base_of<MyClass, std::remove_pointer<T>::type>{}));
}
template <typename T> T* CheckType(T*, std::false_type, std::false_type) const {
std::cout << " Case 1";
return ((T*)AnOtherPointer);
}
template <typename T> T* CheckType(T*, std::true_type, std::false_type) const {
std::cout << " Case 2";
return ((T*)AnOtherPointer);
}
template <typename T> T* CheckType(T*, std::false_type, std::true_type) const {
std::cout << " Case 3";
JustAVoidPointer = (MyClass*)(new T);
return ((T*)JustAVoidPointer);
}
template <typename T> T* CheckType(T*, std::true_type, std::true_type) const {
std::cout << " Case 4";
JustAVoidPointer = (MyClass*)(new std::remove_pointer<T>::type);
return ((T*)(&JustAVoidPointer));
}
}a;
void main()
{
auto CantUseTheStructsName = [&]() {
struct Rnd : public MyClass {};
int x = a; //Case 1
int& y = a; //Case 1
int* z = a; //Case 2
Rnd j = a; //Case 3
Rnd& k = a; //Case 3
Rnd* f = a; //Case 4
char* xx=0; std::cin >> xx;
}; CantUseTheStructsName();
}

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

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

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

boost::variant and function overload resolution

The following code doesn't compile:
#include <boost/variant.hpp>
class A {};
class B {};
class C {};
class D {};
using v1 = boost::variant<A, B>;
using v2 = boost::variant<C, D>;
int f(v1 const&) {
return 0;
}
int f(v2 const&) {
return 1;
}
int main() {
return f(A{});
}
both gcc and clang complains with:
test1.cpp: In function ‘int main()’:
test1.cpp:18:17: error: call of overloaded ‘f(A)’ is ambiguous
return f(A{});
^
test1.cpp:18:17: note: candidates are:
test1.cpp:11:5: note: int f(const v1&)
int f(v1 const&) {
^
test1.cpp:14:5: note: int f(const v2&)
int f(v2 const&) {
Given that is not possible to construct a v2 object from an A instance why the compiler gives the same priority to both functions during the overload resolution?
The problem is the constructor
template<typename T>
variant(const T&)
of boost::variant. The code below reproduces the problem without all the magic:
struct C {};
struct A {
A(const C&) {}
template<typename T>
A(const T&) {}
};
struct B {
template<typename T>
B(const T&) {}
};
int f(const A&) {
return 0;
}
int f(const B&) {
return 1;
}
int main() {
return f(C{});
}
I think the variant constructor should only be enabled if the
argument is actually convertible to the arguments, you might want to
raise this as a bug.
A pragmatic approach, short of fixing the conversion with explicit conversion with proper SFINAE (I don't think it can be done elegantly outside the Boost Variant library), could be this:
See it Live On Coliru
#include <boost/variant.hpp>
class A {};
class B {};
class C {};
class D {};
using v1 = boost::variant<A, B>;
using v2 = boost::variant<C, D>;
namespace detail {
struct F : boost::static_visitor<int> {
template <typename... T>
int operator()(boost::variant<T...> const& v) const {
return boost::apply_visitor(*this, v);
}
int operator()(A) const { return 0; }
int operator()(B) const { return 0; }
int operator()(C) const { return 1; }
int operator()(D) const { return 1; }
} _f;
}
template <typename T>
int f(T const& t) {
return detail::F()(t);
}
int main() {
std::cout << f(A{}) << "\n";
std::cout << f(B{}) << "\n";
std::cout << f(C{}) << "\n";
std::cout << f(D{}) << "\n";
std::cout << f(v1{}) << "\n";
std::cout << f(v2{}) << "\n";
}
Prints
0
0
1
1
0
1
The assumption is that f(T) always returns the same value for the same T even if it is the member of more than one variant