Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ variable that holds any specialization of class template

I need to be able to store any specialization of a template in a variable eg:

template<T>
class Grid {
  int GetRows();
  int GetTypeOfColumn(int col);
  //...etc...
}

//EDIT:
Grid<int>::GetTypeofColumn(int col) {
   return col == 0 ? STRING_COL_TYPE : INT_COL_TYPE;
}
Grid<string>::GetTypeofColumn(int col) {
   return STRING_COL_TYPE;
}
//End EDIT

class Foo {
  Grid<int>* aBunchOfNumbers;
  Grid<string>* aBunchOfStrings;
  //...etc...
}

//in some function, say `wants` is an enum, and foo is gotten from somewhere:
Foo* foo; 
switch wants {
  case NUMBERS:
    std::cout << "Rows: " << foo->aBunchOfNumbers->GetRows() << std::endl;
    std::cout << "Col0 is: " << foo->aBunchOfNumbers->GetTypeofColumn(0) << std::endl;
    //...etc...
    break;
  case STRINGS:
    std::cout << "Rows: " << foo->aBunchOfNumbers->GetRows() << std::endl;
    std::cout << "Col0 is: " << foo->aBunchOfNumbers->GetTypeofColumn(0) << std::endl;
    //...etc...
    break;
}

it would be easier to do:

Foo* foo;
Grid* grid;
switch wants {
  case NUMBERS:
    grid = foo->aBunchOfNumbers;
    break;
  case STRINGS:
    grid = foo->aBunchOfStrings;
    break;
}
std::cout << "Rows: " << grid->GetRows() << std::endl;
std::cout << "Col0 is: " << grid->GetTypeofColumn(0) << std::endl;
//...etc...

In the same way if I used subclasses like this: http://ideone.com/MPKy1w

I'm aware that class templates are almost basically macros and how the compiler actual compiles them, but is there no way to refer to the specializations generically and save repetition?

(I'm using pointers deliberately here, I have no choice in my actual code, which I can not copy here)

like image 431
Jonathan. Avatar asked Mar 12 '23 12:03

Jonathan.


1 Answers

Create class with desired methods ("interface"). It is possible to do so because your methods do not depend on template argument T:

class GridOperations {
    virtual int GetRows() = 0;
    virtual int getTypeOfColumn(int col) = 0;
    virtual ~GridOperations() {}
};

Now inherit Grid from above class:

template<T>
class Grid : public GridOperations {
  int GetRows() { /* impl */ }
  int GetTypeOfColumn(int col) { /* impl */ }
};

Now you may cast both Grid<int>* and Grid<string>* to GridOperations*:

Foo* foo;
GridOperations* ops;
switch wants {
  case NUMBERS:
    ops = foo->aBunchOfNumbers;
    break;
  case STRINGS:
    ops = foo->aBunchOfStrings;
    break;
}
std::cout << "Rows: " << ops->GetRows() << std::endl;
std::cout << "Col0 is: " << ops->GetTypeofColumn(0) << std::endl;

Bonus: and you may even use std::map<WantEnumType, GridOperations*> to avoid nasty switch block.

like image 115
gudok Avatar answered Apr 30 '23 23:04

gudok