C++ conversion derived classes - c++

I have a problem with the code below (c++). I try to explain what I need. I have a base class template and two inherited classes that differ for methods. For each inherited class I need to create the constructor/method that convert the class in the other. The errors are indicated.
template < typename T > class A{
protected:
T **m;
void allocate_mem(T ***ptr){
*ptr = new T*[1];
(*ptr)[0] = new T[1];
}
public:
A(){
throw logic_error("Error!");
}
void renew(T val){
m[0][0] = val;
}
~A(){
delete[] m[0];
delete[] m;
}
T say_elem(){
return m[0][0];
}
};
template < typename T > class B: public A< T >{
public:
B(int val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = val;
}
B(const C &c){ //'C' does not name a type
//ISO C++ forbids declaration of 'c' with no type [-fpermissive]
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = A<T>::c.say_elem();
}
};
template < typename T > class C: public A< T >{
public:
C(double val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = 1;
}
C(const B &b){ //'B' does not name a type
//ISO C++ forbids declaration of 'b' with no type [-fpermissive]
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = A<T>::b.say_elem();
}
};
What I have to do? Thanks for the help!

To fix the "does not name a type" errors, try forward declaring your classes (ie, put the following lines at the top of your file).
template < typename T > class A;
template < typename T > class B;
template < typename T > class C;
Then change this: B(const C &c) to this: B(const C<T> &c), and the same for the C constructor.
The following code compiles for me:
template < typename T > class A {
protected:
T **m;
void allocate_mem(T ***ptr){
*ptr = new T*[1];
(*ptr)[0] = new T[1];
}
public:
A() { throw logic_error("Error!"); }
void renew(T val) { m[0][0] = val; }
~A() {
delete[] m[0];
delete[] m;
}
T say_elem() { return m[0][0]; }
};
template < typename T > class C;
template < typename T > class B: public A< T >{
public:
B(int val) {
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = val;
}
B(const C<T> &c) {
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = A<T>::c.say_elem();
}
};
template < typename T > class C: public A< T >{
public:
C(double val) {
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = 1;
}
C(const B<T> &b) {
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = A<T>::b.say_elem();
}
};

The forward declaration answer is almost right, but forward declarations can't specify the parent class. Forward declare like this:
template < typename T > class A;
template < typename T > class B;
template < typename T > class C;

You have some circular dependencies between your classes. At a minimum you'll need to provide some forward declarations of your classes. Even then you may need to change the references to pointers because of the method declaration order.

Related

Covariant return type with primitive types

I have the following:
template<typename T>
class AbsContainer {
public:
virtual T operator[](ptrdiff_t) = 0;
};
template<typename T>
class SpecialContainer : public AbsContainer<T>, Box<pair<ptrdiff,T>> {
class Proxy;
public:
Proxy operator[](ptrdiff_t i) {
return Proxy(i, this);
};
};
template <typename T>
class SpecialContainer<T>::Proxy {
ptrdiff_t _i;
Box* _p;
public:
Proxy(ptrdiff_t i, Box* p) : _i(i), _p(p);
Proxy& operator=(const T& elm) {
_p->::insert(pair<ptrdiff,T>(_i,elm)); //defined in Box
}
};
main:
SpecialContainer<int> x;
x[2] = 3;
This doesn't compile, because in class SpecialContainer, the operator[] with the one in AbsContainer.
Ideally in concept, Proxy operator[] should be an override. So I tried resolving this by achieving covariant return type by making Proxy inherit from T. However it doesn't work since T can be a primitive type, and inheriting from a primitive type has no sense.
Error because of operator conflict :
error: conflicting return type specified for ‘specialContainer<T>::Proxy B<T>::operator[](std::ptrdiff_t) [with T = int; std::ptrdiff_t = long unsigned int]
Error because trying to inherit from parametric type T (int in this case):
error: base type ‘int’ fails to be a struct or class type
Is there any way in which can this be resolved ?
You can implement something very similar to covariant types even without any compiler support for actual covariant types. Here's how to do it.
#include <cstddef>
#include <map>
#include <string>
#include <iostream>
template<typename T>
class AbsContainer {
public:
T operator[](ptrdiff_t i) { return operator_Abs(i); }
virtual T operator_Abs(ptrdiff_t) = 0;
};
template<typename T>
class SpecialContainer : public AbsContainer<T>, std::map<ptrdiff_t, T> {
public:
class Proxy;
Proxy operator[](ptrdiff_t i) { return operator_Spec(i); }
T operator_Abs(ptrdiff_t i) override {
return operator_Spec(i).get();
}
virtual Proxy operator_Spec(ptrdiff_t i) {
return Proxy(i, this);
}
};
template <typename T>
class SpecialContainer<T>::Proxy {
ptrdiff_t _i;
std::map<ptrdiff_t, T>* _p;
public:
Proxy(ptrdiff_t i, std::map<ptrdiff_t, T>* p) : _i(i), _p(p) {};
Proxy& operator=(const T& elm) {
_p->insert(std::pair<ptrdiff_t,T>(_i,elm));
return *this;
}
T get() { return (*_p)[_i]; }
};
int main()
{
SpecialContainer<std::string> spec;
AbsContainer<std::string>& abs = spec;
auto k = spec[42];
k = "Hello World";
std::cout << abs[42] << "\n";
}

C++ access inner class in a template

pls have a look at this code:
template<typename T>
class myclass {
private:
class node {
friend class myclass;
T t;
node(T t_) : t(t_) {};
};
node nd;
node getNode();
public:
myclass(T t_) : nd(node(t_)) {};
T get() {
auto node = getNode();
return node.t;
}
};
template<typename T>
myclass<T>::node myclass<T>::getNode() {
return nd;
}
I define the method getNode() outside the template, and the compiler report this error:
missing 'typename' prior to dependent type name 'myclass<T>::node'
myclass<T>::node myclass<T>::getNode() {
how should I write it correctly?
Need to use typename keyword for dependent type myclass<T>
template<typename T>
typename myclass<T>::node myclass<T>::getNode() {
~~~~~~~~
return nd;
}

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++ derived classes, one is the argument of the other

I have a problem with two derived classes. I need that one receive the other as argument, but my code doesn't work (I semplified it to be more clear).
class:
#include<iostream>
#include<stdexcept>
using namespace std;
template <typename T> class A;
template <typename T> class B;
template <typename T> class C;
template <typename T> class A{
protected:
T **m;
void allocate_mem(T ***ptr){
*ptr = new T*[1];
(*ptr)[0] = new T[1];
}
public:
A(){
throw logic_error("Error!");
}
~A(){
delete[] m[0];
delete[] m;
}
T say_elem(){
return m[0][0];
}
};
template <typename T> class B: public A<T>{
public:
B(int val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = val;
}
};
template <typename T> class C: public A<T>{
public:
C(double val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = 1;
}
void renew(const B<T> &b){
if(A<T>::b.say_elem() > 0){
A<T>::m[0][0] = 1000;
}
}
};
main:
#include<iostream>
#include "class.cpp"
using namespace std;
int main(int argc, char **argv){
B <int> bbb(4);
C <double> ccc(5);
ccc.renew(bbb);
//no matching function for call to 'C<double>::renew(B<int>&)'
return 0;
}
the error is indicated above, what i need to do?
You are trying to call C<T>::renew(const B<T> &) with the wrong argument. What renew is expecting (in the call to the instance C<double>) is const B<double>&, not const B<int>&. They are two completely different classes. If you want to allow a B class with a different template parameter, templatize the function:
template<class U>
void renew(const B<U> &b) {
if(b.say_elem() > 0){
m[0][0] = 1000;
}
}
Ok, I combined Jefffrey's correct answer with my note from the comments to give a complete compiling and running code (which will throw logic_error("Error!") by the way, but this is off-topic).
#include<iostream>
#include<stdexcept>
using namespace std;
template <typename T> class A;
template <typename T> class B;
template <typename T> class C;
template <typename T> class A{
protected:
T **m;
void allocate_mem(T ***ptr){
*ptr = new T*[1];
(*ptr)[0] = new T[1];
}
public:
A(){
throw logic_error("Error!"); // remove this line for expected behavior
}
~A(){
delete[] m[0];
delete[] m;
}
T say_elem() const {
return m[0][0];
}
};
template <typename T> class B: public A<T>{
public:
B(int val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = val;
}
};
template <typename T> class C: public A<T>{
public:
C(double val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = 1;
}
template <typename U>
void renew(const B<U> &b){
if(b.A<U>::say_elem() > 0){
A<T>::m[0][0] = 1000;
}
}
};
int main(int argc, char **argv){
B <int> bbb(4);
C <double> ccc(5);
ccc.renew(bbb);
return 0;
}

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.