Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get instance of class template out of the if statement? (C++)

Suppose I have a class template which have a member pData, which is an AxB array of arbitary type T.

template <class T> class X{ 
public:
    int A;
    int B;
    T** pData;
    X(int a,int b);
    ~X();        
    void print(); //function which prints pData to screen

};  
template<class T>X<T>::X(int a, int b){ //constructor
    A = a;
    B = b;
    pData = new T*[A];
    for(int i=0;i<A;i++)
        pData[i]= new T[B];
    //Fill pData with something of type T
}
int main(){
    //...
    std::cout<<"Give the primitive type of the array"<<std::endl;
    std::cin>>type;
    if(type=="int"){
        X<int> XArray(a,b);
    } else if(type=="char"){
        X<char> Xarray(a,b);
    } else {
        std::cout<<"Not a valid primitive type!";
    } // can be many more if statements.
    Xarray.print() //this doesn't work, as Xarray is out of scope.
}

As the instance Xarray is constructed inside of an if statement, I cannot use it anywhere else. I tried to make a pointer before the if statements but as the type of the pointer is unknown at that point, I did not succeed.

What would be a proper way of dealing with this kind of a problem?

like image 907
Jouni Helske Avatar asked Feb 20 '13 12:02

Jouni Helske


People also ask

Can you derive template classes?

Deriving from a non-template base classIt is quite possible to have a template class inherit from a 'normal' class. This mechanism is recommended if your template class has a lot of non-template attributes and operations. Instead of putting them in the template class, put them into a non-template base class.

Can default argument be used with the template class?

Can default arguments be used with the template class? Explanation: The template class can use default arguments.

How do you declare a template class?

To instantiate a template class explicitly, follow the template keyword by a declaration (not definition) for the class, with the class identifier followed by the template arguments. template class Array<char>; template class String<19>; When you explicitly instantiate a class, all of its members are also instantiated.

What is Oops template function?

A function template is a generic function that is defined on a generic type for which a specific type can be substituted. Compiler will generate a function for each specific type used. Because types are used in the function parameters, they are also called parameterized types.


1 Answers

The problem here is that X<int> and x<char> are completely unrelated types.

The fact that they are both a result of the same templated class won't help here.

I can see several solutions, but those depends on what you really need.

You could, for instance make the X<> instances derive from a common non-templated base class that has the print() method (eventually as a pure virtual). But before you do that, be sure that it makes sense on a functional level: one should use inheritance because it makes sense, not solely because of technical constraints. And if you do that, you probably will want to have a virtual destructor as well.

You could also bind and store a std::function<void ()> to the method you want to call, but ensure that the objects are still "alive" (they aren't in your current code: both the X<int> and X<char> are destroyed when they go out of scope, way before you actually call print()).

A final solution would be to make some variant type that is compatible with both X<int> and X<char> (boost::variant<> can help here). You could then write a visitor that implements the print() functionality for each type.

Picking the last solution, it would become something like:

typedef boost::variant<X<int>, X<char>> genericX;

class print_visitor : public boost::static_visitor<void>
{
public:
    template <typename SomeType>
    void operator()(const SomeType& x) const
    {
        // Your print implementation
        // x is your underlying instance, either X<char> or X<int>.
        // You may also make several non-templated overloads of
        // this operator if you want to provide different implementations.
    }
};

int main()
{
  boost::optional<genericX> my_x;

  if (type=="int") {
    my_x = X<int>(a,b);
  } else if(type=="char") {
    my_x = X<char>(a,b);
  }

  // This calls the appropriate print.
  if (my_x) {
    boost::apply_visitor(print_visitor(), *my_x)
  }
}

We actually lack the knowledge to give a definitive answer: if your classes are "entities", then you probably should go for inheritance. If they are more like "value classes", then the variant way might be more suited.

like image 155
ereOn Avatar answered Sep 18 '22 19:09

ereOn