Derived pointer auto-drop

Good morning,

I have a templatized class and I want to manipulate objects with a pointer vector. To use a pointer vector for a template class, I need this class, which must be derived from an unclassified class, and I did it.

Here is my problem: call the derived class method from the pointer to the base class, I can not use virtual functions, because template functions cannot be made virtual. I need to make an explicit conversion, which is tedious: if you create a numerical object with a new one, in fact, you need to make it down to number *, although it is known that the object is a number in advance.

I solved this problem awkwardly: the myset function checks all supported typeid values ​​to get the correct dynamic translation. This is a long series of nested ifs that do type checking.

In addition to tediousness, the function works only to call the "set" method, and similar functions must be defined to call other methods. If I could do an automatic casting on the object that I am pointing to, everything will be much simpler.

Disadvantages of the approach:

  • the code repeats: if I defined another function (for example, T get () {return val;}, I would need another myget function with a full set of nested ifs!
  • the list of supported types should be explicitly defined by nesting if calls
  • code may be inefficient

The compiler knows that lst [0] (in the code below) points to a numerical object, although lst is a vector of objects of the element from which the number <> of objects is deduced.

Is there a way to automatically lower a pointer, defined as base *, to a pointer to an object actually pointed to?

If I had the correct downgrade, then I could define thousands of methods in the class number <> and call them with a call to the wellcasting function β†’ (...)

Here's the code (it works correctly, the kernel is the definition of "myset")

Thanks in advance, Pietro M.

PS I am most interested in the standard approach in C ++ without using libraries other than STL, such as Boost.

#include <iostream> #include <vector> #include <typeinfo> using namespace std; class element { public: virtual void print() = 0; // print is not templatized and works properly //template <class T> virtual set(T v) = 0; // this would solve all my problems, if only it were legal. }; template <class T> class number : public element { T val; public: void print() {cout << "number is " << val << endl;} void set(T v) {val = v;} }; // That the best I can do! template <class T> void myset(T v, element *ptr) { // There is a kink in the template: the compiler checks the T type by the value of v, that in this case is an integer: // cout << "Type name for the template is: " << typeid(T).name() << endl; // cout << "Type name for an integer is: " << typeid(int).name() << endl; if (typeid(*ptr) == typeid(number<double>)) { ((number<double> *) ptr) -> set(7); return; } else if (typeid(*ptr) == typeid(number<float>)) { ((number<float> *) ptr) -> set(7); return; } // add other types... (tedious) else { cout << "type not supported" << endl; } } int main() { vector <element *> lst; // list of heterogeneous templatized objects lst.push_back(new number<float>); lst.push_back(new number<double>); lst[0] -> print(); //((number<float> *) lst[0]) -> set(7); it correct but it requires I know the type when I call it (tedious) myset(7, lst[0]); // may be inefficient, but it works (for the types which are explicitly supported) // cast_to_what_the_pointer_actually_points_to <lst[0]> -> set(7); // that what I'd like to do: a downcast function which checks the object type and returns the correct pointer would be able to call any class method... lst[0] -> print(); } 
+4
source share
1 answer

You are almost there. You need to have a templated set method that calls a private virtual method with a typeid and void * pointer to its argument, allowing the override to decide how to handle it:

 class element { virtual void set_impl(const std::type_info &, const void *) = 0; public: template <class T> void set(T v) { set_impl(typeid(v), &v); } }; 

And an example of how to write set_impl :

 template <class T> class number : public element { T val; void set_impl(const std::type_info &ti, const void *pv) { if (ti == typeid(T)) { val = *static_cast<const T *>(pv); } else { throw std::invalid_argument("incorrect type to set()"); } } }; 

This is similar to the approach made by Boost.Any .

+3
source

Source: https://habr.com/ru/post/1492670/


All Articles