-2

Long story short, what I want here is to declare a templated type in a base class and be able to access that type A<T> such that the base class B contains it and the derived class C is able to access it as C::A<T>. I did try declaring an int inside of class B and that can be accessed from the derived C class as C::int, here's the error!

||In constructor ‘D::D()’:|
|74|error: no match for ‘operator=’ (operand types are ‘A<C*>’ and ‘A<B*>’)|
|4|note: candidate: A<C*>& A<C*>::operator=(const A<C*>&)|
|4|note:   no known conversion for argument 1 from ‘A<B*>’ to ‘const A<C*>&’|

And this is the code that does compile ( comment A<B*> i; and uncomment A<C*> i; to get the error).

#include <iostream>
//class with a template parameter
template <class a>
class A
{
    private:

        int somevalue;

    public:

    A(){}
    ~A(){}
    void print()
    {
        std::cout<<somevalue<<std::endl;
    }
};

//1. could forward declare
class C;
class B
{
    protected:

        A<B*> i;
        //2. and then use
        //A<C*> i;

    public:

        B(){}
        ~B(){}
        A<B*> get()
        {
            return i;
        }

        /*
        //3. use this return instead
        A<C*> get()
        {
            return i;
        }
        */
};
//specialization of B that uses B's methods variables
class C : public B
{
    protected:

    public:

        C(){}
        virtual ~C(){}
        void method()
        {
            B::i.print();
        }
};
//class D that inherits the specialization of C
class D : public C
{
    private:

        A<B*> i;//works
        //4. but I want the inherited type to work like
        //A<C*> i;// so that the type C* is interpreted as B*

    public:

    D()
    {
        this->i = C::i;
    }
    ~D(){}
};
///////////////////////////////////////////////////////////////////////
int main()
{
    D* d = new D();

    delete d;

    return 0;
}
pandoragami
  • 5,387
  • 15
  • 68
  • 116
  • "This would solve the whole problem but it's not portable and C++ like." explain? – xaxxon Jun 24 '17 at 05:50
  • I don't want to declare that class name every time I want to use that class. isn't there a different method of instantiating this, given that I would want a header file stored somewhere without know its contents. – pandoragami Jun 24 '17 at 05:51
  • 1
    Is this the long-time favorite of MyTemplate and MyTemplate types aren't related by inheritance problem? I can't actually understand your question. It's very long and rambling and you have WAY more code in your example than you need. – xaxxon Jun 24 '17 at 05:52
  • Is it, is there a solution, cause i've tried for hours now, mark it as duplicate if you like! Yes that does sound like the problem. – pandoragami Jun 24 '17 at 05:53
  • "Is this the long-time favorite of MyTemplate and MyTemplate types aren't related by inheritance problem? I can't actually understand your question. It's very long and rambling and you have WAY more code in your example than you need" I know, but the code does explain it better. I guess. – pandoragami Jun 24 '17 at 05:56
  • Template and Template don't inherit from each other, regardless of the relationship between X and Y -- unless the template itself explicitly states the relationship..template Template : public Template {}; or some such. – xaxxon Jun 24 '17 at 05:57
  • So the only solution is to declare everything with that template argument in the derived class as well right, then what's the point of inheritance? – pandoragami Jun 24 '17 at 05:58
  • 3
    I'm sorry, I don't actually understand what your goal is, so I can't tell you how to change your code to suit it. I can tell you that you don't need this behavior to achieve your goal... but I don't know what option would be best for you based on the example above. I also don't seem to be able to find a dupe, though I know I've seen it many times in the past. – xaxxon Jun 24 '17 at 06:00
  • The goal is the code above, generally written as simple as possible. What I could do is write the method in the derived class for the `get()` function for the template argument of the derived class and that would solve the problem. – pandoragami Jun 24 '17 at 06:02
  • It would probably be better to write an example main function with the wanted behavior ... it's absolutely impossible to get what you're trying to achieve here ... – Daniel Jour Jun 24 '17 at 06:04
  • You mean to get rid of `class D` ? – pandoragami Jun 24 '17 at 06:05
  • "You get a compiler error saying it cannot convert B* to C* obviously." That's not what it's saying. It's saying you can't change an `A` to a `A`. There is a relationship between `B` and `C`, but the same can't be said for two different specializations of `A`. – user4581301 Jun 24 '17 at 06:08
  • `A` doesn't use its template argument so I don't understand what you mean by "I want `A i` to work like `A i`". All types `A` work the same way. – melpomene Jun 24 '17 at 06:08
  • So there is basically no solution to this problem and I'm just misusing C++? – pandoragami Jun 24 '17 at 06:09
  • No, there is no problem (or rather your description makes no sense). Can you show actual code that demonstrates the problem? – melpomene Jun 24 '17 at 06:10
  • That is the code, that's all I have! – pandoragami Jun 24 '17 at 06:11
  • Then the solution is to get rid of the template and make `A` a plain class. – melpomene Jun 24 '17 at 06:12
  • Btw: from `B*` to `C*` isn't that good an idea either, you need to explicitly downcast (and check whether it succeed). – Daniel Jour Jun 24 '17 at 06:15
  • 2
    @pandoragami No, it isn't. `A` is a class template you created in your code ("*that's all I have!*"). If you have some other, actual code, you need to post that. – melpomene Jun 24 '17 at 06:17

3 Answers3

2

But okay what if we tried this std::list<template parameter> LIST and then plug that in? That's the problem A<T> is std::list.

As far as I understand your issue now you seem to have a std::list<Base *> (renamed B to Base for clarity) and want to fill an std::list<Concrete*> (renamed C to Concrete, it's derived from Base) with it.

For that you need to iterate over the Base* pointers, checking for each whether it can be downcast to a Concrete* and if so adding it to the std::list<Concrete*>. You need to think about what to do if the downcast fails, too.

For all of this to work your Base needs to be a polymorphic base class, that is it must contain a virtual member function (don't forget to make the destructor virtual). Also note that this sounds like a catastrophe waiting to happen in terms of managing ownership of those pointers.

template<typename Base, typename Concrete>
std::list<Concrete*> downcast_list (std::list<Base*> const & bases) {
 std::list<Concrete*> result;
  for (auto const base_ptr : bases) {
    Concrete * concrete_ptr = dynamic_cast<Concrete*>(base_ptr);
    if (concrete_ptr != nullptr) {
      result.push_back(concrete_ptr);
    } else {
      // Error or ignore?
    }
  }
  return result;
}

Note: a more idiomatic version of this would use iterators.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
1

I found the pattern to my problem, it's actually really simple and it serves as the base for encapsulating a class type a (which is a template parameter to be passed around, try looking at my question as a reference to class a). The pattern is shown below, it's generally what I wanted. I found it on this webpage Using Inheritance Between Templates chapter 7.5 from the book entitled OBJECT-ORIENTED SOFTWARE DESIGN and CONSTRUCTION with C++ by Dennis Kafura. I'll copy it below the edited code for the sake of future reference in case anyone else needs it.

template <class a> 
class B 
{
    private:      

    public:

        B();     
        ~B();
};

template <class a> 
class C : public B<a>
{
   public:
    C();
    ~C();
};

This is the code it was adapted from.

template <class QueueItem> class Queue 
{
   private:

      QueueItem buffer[100];
      int head, tail, count;

    public:
                Queue();
      void      Insert(QueueItem item);
      QueueItem Remove();
               ~Queue();
};

template <class QueueItem> class InspectableQueue : public Queue<QueueItem>
{
   public:
               InspectableQueue();
     QueueItem Inspect();  // return without removing the first element
              ~InspectableQueue();
};
pandoragami
  • 5,387
  • 15
  • 68
  • 116
-1

Try changing this:

#include <iostream>
//class with a template parameter
template <class a>
class A {
private:    
    int somevalue;    
public:    
    A(){}
    ~A(){}
    void print() {
        std::cout<<somevalue<<std::endl;
    }
};

//1. could forward declare
class C;
class B {
protected:    
    A<B*> i;
    //2. and then use
    //A<C*> i;    
public:    
    B(){}
    ~B(){}
    A<B*> get() {
        return i;
    }

    /*/3. use this return instead
    A<C*> get() {
       return i;
    } */
};

//specialization of B that uses B's methods variables
class C : public B {
protected:
public:    
    C(){}
    virtual ~C(){}
    void method() {
        B::i.print();
    }
};    

//class D that inherits the specialization of C
class D : public C {
private:   
    A<B*> i;//works
    //4. but I want the inherited type to work like
    //A<C*> i;// so that the type C* is interpreted as B*
public:    
    D() {
        this->i = C::i;
    }
    ~D(){}
};

   int main() {
    D* d = new D();    
    delete d;    
    return 0;
}

To Something Like This:

#include <iostream>

//class with a template parameter
template <typename T>
class Foo {
private:    
    T value_;    
public:    
    Foo(){} // Default
    Foo( T value ) : value_(value) {}
    ~Foo(){}
    void print() {
        std::cout<< value_ << std::endl;
    }
};

class Derived;
class Base {
protected:
    Foo<Base*> foo_;
    Base(){} // Default;
    virtual ~Base(){}

    // Overload This Function
    template<typename T = Base>
    /*virtual*/ Foo<T*> get();

    /*virtual*/ Foo<Base*> get() { return this->foo_; }
    /*virtual*/ Foo<Derived*> get();
};

class Derived : Base {
public:
    Derived() {}
    virtual ~Derived() {}

    void func() {
        Base::foo_.print();
    }
    void Foo<Derived*> get() override { return this->foo_; } 
 };

And this is as about as far as I could get trying to answering your question...

  • There are objects that you are not using in your code
  • There are methods that aren't being called.
  • It is kind of hard to understand the direction/indirection of what you mean to do with the inheritance tree.
  • You are inheriting from a base class without a virtual destructor
  • And probably a few other things that I can not think of off the top of my head right now.

I'd be more than willing to try and help you out; but this is as far as I can go with what you currently are showing.

EDIT -- I made changes to the base & derived classes and removed the virtual keyword to the overloaded function template declarations - definitions belonging to those classes.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • @pandoragami no problem at all; I'm self taught, never had any formal training nor any college courses, never had someone sit there and teach it all to me. I had to find what few books I could get, I had to read a bunch of mundane and archaic type websites going as far back as the mid to late 90s even when `ftp` sites were still widely used. I had to do a bunch of trial and errors and many failures just to even get simple things to work. Then it took time to learn the language; and I'm still currently learning. Sometimes helping others helps me to learn for I have to stop and think about it. – Francis Cugler Jun 24 '17 at 20:33
  • Sorry but your code doesn't work, you cannot use virtuals and templates together. – pandoragami Jun 25 '17 at 23:27
  • Oh; yeah... I'm still learning templates myself, they are one of the harder parts of the C++ language to master. Yes you can leave the destructor as virtual and any non template methods or functions as virtual but for any overloaded template functions belonging to the class; virtual storage won't work. – Francis Cugler Jun 25 '17 at 23:34
  • I added my answer to my question, it sort of solved ( not exactly) my problem and didn't need anything overly complicated. It seems though that there is no real easy method of inheriting a datatype with a template parameter and it must be defined (specialized) in the derived class no matter what. My solution only encapsulates the datatype as a template parameter so it's passed around instead! It's better than nothing and that's the best it can get using simple C++ coding. – pandoragami Jun 26 '17 at 04:28