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