How do i fix conversion error in the following code? - c++

I have a template class:
template<class T>
class A{
T a, b;
public:
A(A<T> const & o) : a(o.a), b(o.b){}
A(T const & _a, T const & _b) : a(_a), b(_b){}
};
A<double> d(1.2, 4.5);
A<float> f = d; //error: conversion from A<double> to non-scalar type A<float> requested
How do i define a conversion function for my class?
My compiler is g++ 4.7.0

You could make a template constructor:
template<class T>
class A{
T a, b;
public:
template<class U>
A(A<U> const & rhs) : a(rhs.a), b(rhs.b) {}
A(T const & _a, T const & _b) : a(_a), b(_b){}
};
Then you should be able to convert any class A<U> to any class A<T> as long as U is convertible to T.

What you're trying to do is not a good idea.
However, to get over the compiler error, you can specialize the class -
template <>
class A<float>
{
public:
A(A<double> const & o) {}
};

Related

Why does a generic type that can be casted not get implicitly converted?

I have a class A and a class B, both generic with a type parameter T. An object of A<T> can be casted to B<T>. I have a generic operator overload on B that I want to be able to call on an A object and a B object, where the A object gets implicitly converted.
When I try this it does not compile:
template <typename T>
class A {};
template <typename T>
class B {
public:
B() {}
B(const A<T> &a) {}
};
template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
return B<T>(); // doesn't matter
}
int main() {
A<int> objA;
B<int> objB;
B<int> combined1 = objA * objB; // error: operator* isn't defined on these types
B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine
return 0;
}
However when A and B aren't generic, it works fine:
class A {};
class B {
public:
B() {}
B(const A &a) {}
};
B operator*(const B &obj1, const B &obj2) {
return B(); // doesn't matter
}
int main() {
A objA;
B objB;
B combined1 = objA * objB; // fine
B combined2 = static_cast<B>(objA) * objB; // also fine
return 0;
}
Why is this? Is there something about making the operator overload generic that means the type can't be inferred?
In general, implicit conversions are not allowed while doing argument deduction, I can think of a derived to base as one that is allowed. The expression
B<int> combined1 = objA * objB;
expect to find viable overloads for objA * objB, including those found by ADL, one possible is:
template <typename T>
B<T> operator*(const A<T> &obj1, const B<T> &obj2) {...}
but none is found, the overload you provide is not a candidate, hence the call fail, but if you provide the explicit template argument to the operator, then there will be nothing to deduce and the implicit conversion through the converting constructor will allow the call:
B<int> combined1 = operator*<int>(objA, objB);
But I would not do that, stick with the cast it better explain the intent.
You can define friend function in class A which call your template function
template <class T>
class B;
template <typename T>
class A {
friend B<T> operator*(const B<T> &obj1, const B<T> &obj2) {} # here call template function
};
template <typename T>
class B {
public:
B() {}
B(const A<T> &a) {}
};
template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
return B<T>(); // doesn't matter
}
int main() {
A<int> objA;
B<int> objB;
B<int> combined1 = objA * objB; // fine
B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine
return 0;
}
During argument deduction, conversion/promotion doesn't occurs, so for
objA * objB
When checking validity of candidates overload, T cannot be deduced for:
template <typename T> B<T> operator*(const B<T> &, const B<T> &);
So that overload is rejected.
One way to fix that is to create a non template function. Asit should apply to classe template, one way to do it is with friend functions:
template <typename T>
class B {
public:
B() {}
B(const A<T>&) {}
friend B operator*(const B&, const B&) { return /*...*/; }
};
Now, objA * objB considers overload B<int> operator*(const B<int>&, const B<int>&) and conversion can occurs to see if function is viable (and it is).
Demo

Inherit operators defined outside class

In this minimal example I have a class A with an operator + defined outsise of it:
template<class T> class A {};
template<class T1, class T2> void operator+(A<T1> a, A<T2> b) {}
template<class T> class B : public A<T> {};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
I've tried to create an implicit conversion from B to A but it requires the operator+ to be a friend of A and be defined inside A which will cause problems when more than one instance of A<...> gets instantiated.
So, is there any other way to do this without having to define the operator+ again?
Thank you in advance for any help.
template<class T> class A {
template<class T2>
friend void operator+(A const& lhs, A<T2> const& rhs) {}
};
template<class T> class B : public A<T> {};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
this works. The assymetry in + (one template, one not) ensure that multiple As don't conflict with their +.
In some situations you really need lhs to be an instance of B:
template<class T> struct A {
template<class D, class T2, std::enable_if_t<std::is_base_of<A, D>{}, bool> =true >
friend void operator+(D const& lhs, A<T2> const& rhs) {
std::cout << D::name() << "\n";
}
static std::string name() { return "A"; }
};
template<class T> struct B : public A<T> {
static std::string name() { return "B"; }
};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
which uses A's operator+, but the LHS is of type B. Doing this for B<T2> on the right hand side isn't very viable, it gets ridiculous.

C++ templated class self-inheritance

I've got this code:
template<typename A, typename B = A>
class MyClass;
template<typename A>
class MyClass<A, void>
{
protected:
A a;
MyClass<A, void>(const A& a):
a(a)
{}
public:
const A& getA() const
{
return a;
}
};
template<typename A, typename B>
class MyClass : public MyClass<A, void>
{
private:
B b;
public:
MyClass<A, B>(const A& a, const B& b):
MyClass<A, void>(a), b(b)
{}
const B& getB() const
{
return b;
}
const auto getAplusB() const
{
return a+b;
}
};
getAplusB method fails to compile with message a is not declared. However, inheritance seems to work, so I can use this->getA() + b. I've also tried to do dynamic_cast<const MyClass<A, void>*>(this)->a + b, but got another compilation error a is protected. What am I missing here?
You will need to simply use this->a or a qualified name MyClass<A, void>::a. This is because a is member of a base class-template. There is such a thing known as name lookup - When the compiler sees a name, it does the said name lookup.
Simply trying to make unqualified accesses a will not work because it's a dependent name (by meaning of it depending on the instantiation of some template somewhere). Hence you have to qualify the accesses to a

Template friend function and return type deduction

Note: This question is really close to Return type deduction for in-class friend functions, but I did not find the answer to my problem there.
Tested with clang 3.4 with std=c++1y and clang 3.5 with std=c++14 and std=c++1z
This code compiles:
#include <iostream>
template<class T>
class MyClass {
public:
MyClass(T const& a) : impl(a) {}
template<class T0, class T1> friend auto
// requires operator+(T0,T1) exists
operator+(MyClass<T0> const& a, MyClass<T1> const& b)
{
return MyClass<decltype(a.impl+b.impl)>{a.impl + b.impl};
}
T getImpl() const { return impl; }
private:
T impl;
};
int main() {
MyClass<int> x(2);
MyClass<long> y(2);
auto z = x+y;
std::cout << z.getImpl() << "\n";
}
Now if I define operator+ outside of the class, it does not compile anymore:
template<class T>
class MyClass {
public:
MyClass(T const& a) : impl(a) {}
template<class T0, class T1> friend auto
operator+(MyClass<T0> const& a, MyClass<T1> const& b);
T getImpl() const { return impl; }
private:
T impl;
};
template<class T0, class T1> auto
operator+(MyClass<T0> const& a, MyClass<T1> const& b)
{
return MyClass<decltype(a.impl+b.impl)>{a.impl + b.impl};
}
Clang 3.4 says:
error: use of overloaded operator '+' is ambiguous (with operand types MyClass<int> and MyClass<long>)
And then points at what it believes to be two different functions: the declaration in the class and the definition outside the class.
My question is: is it a clang bug, or just that template parameters are deduced for a friend function thus leading the two functions not being equivalent is some cases ?
And what alternative would you suggest: make operator+ a member function, or define friend operator+ inside the class (which would in my opinion clutter the class interface) ?
Just for your information, I have a real use case of such code, where I try to wrap a third -party matrix class and I need return type deduction because of the use of expression template for lazy evaluation.
Edit: The following does work (but still clutters the interface...)
template<typename T>
class MyClass
{
T impl;
public:
explicit MyClass(T a) : impl(std::move(a)) { }
T const& getImpl() const { return impl; }
template<typename T0, typename T1>
friend auto operator +(MyClass<T0> const& a, MyClass<T1> const& b) -> MyClass<decltype(a.impl + b.impl)>;
};
template<typename T0, typename T1>
auto operator +(MyClass<T0> const& a, MyClass<T1> const& b) -> MyClass<decltype(a.impl + b.impl)>
{
return MyClass<decltype(a.impl + b.impl)>(a.impl + b.impl);
}
edit:
look at the comments section, it's a bug in gcc 4.8.2 and 4.9
Gcc error code:
prog.cpp:10:61: error: non-static data member declared 'auto'
operator+(MyClass const& a, MyClass const& b)
^ prog.cpp: In function 'int main()': prog.cpp:25:15: error: no match
for 'operator+' (operand types are 'MyClass' and 'MyClass')
auto z = x+y;
^

Conversion between different template instantiation of the same template

I am trying to write an operator which converts between the differnt types of the same implementation. This is the sample code:
template <class T = int>
class A
{
public:
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
private:
int m_a;
};
int main(void)
{
A<int> a;
A<double> b = a;
return 0;
}
However, it gives the following error for line u.m_a = m_a;.
Error 2 error C2248: 'A::m_a' :
cannot access private member declared
in class
'A' d:\VC++\Vs8Console\Vs8Console\Vs8Console.cpp 30 Vs8Console
I understand the error is because A<U> is a totally different type from A<T>. Is there any simple way of solving this (may be using a friend?) other than providing setter and getter methods? I am using Visual studio 2008 if it matters.
VC10 accepts this:
template <class T = int>
class A
{
public:
template< typename U>
friend class A;
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
private:
int m_a;
};
You can declare the conversion function as friend
template <class T = int>
class A
{
public:
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
template <class U> template<class V>
friend A<U>::operator A<V>();
private:
int m_a;
};
You could construct the A<U> with the int directly.