C ++ 11 Dynamic Cast If Else Chain & # 8594; Switch

Consider the following:

struct B { }; template<typename T> struct D : B { T t; } void g(int i) { ... } void g(string s) { ... } void g(char c) { ... } void f(B* b) { if (dynamic_cast<D<int>*>(b)) { g(dynamic_cast<D<int>*>(b)->t); } else if (dynamic_cast<D<string>*>(b)) { g(dynamic_cast<D<string>*>(b)->t); } else if (dynamic_cast<D<char>*>(b)) { g(dynamic_cast<D<char>*>(c)->t) } else throw error; }; 

There are only three possible types of T-int, string, char - but if the list of possible types was longer, say n, the if else chain could do O (n).

One way to deal with this is to store the additional code code in D in some way, and then switch in the type code.

The RTTI system should already have this code. Is there a way to access it and enable it?

Or is there a better way to do what I'm trying to do?

+4
source share
3 answers

C ++ 11 is almost absent.

In C ++ 03, this was not possible because the only way to get the compile-time constant (which case requires) is through a type system. Since typeid always returns the same type, it cannot create different alternatives for switch .

C ++ 11 adds constexpr and type_info::hash_code as a unique identifier for types, but does not combine them. You can use typeid in a constant expression for a type name or statically typed expressions, but since hash_code is not a constexpr function, you cannot call it.

Of course, there are various workarounds, one of which you describe, and the most common of which apply the visitor to a type vector using metaprogramming of templates.

+3
source

Since only a few types are valid, you can solve this with virtual functions and template specialization:

 struct B { virtual void g() = 0; } template<typename T> struct D : public B { T t; }; template<> struct D<int> : public B { int t; void g() { /* do something here */ } }; template<> struct D<std::string> : public B { std::string t; void g() { /* do something here */ } }; template<> struct D<char> : public B { char t; void g() { /* do something here */ } }; void f(B* b) { b->g(); } 

This will cause a compile-time crash if you provide the wrong types instead or require runtime checks (which is pretty bad in C ++).

+3
source

The primary choice for including on-time in C ++ is a virtual function.

This is dead simple:

 #include <string> #include <iostream> using namespace std; struct Base { virtual void g() const = 0; }; template< class Type > void g( Type const& ); template<> void g( int const& ) { cout << "int" << endl; } template<> void g( string const& ) { cout << "string" << endl; } template<> void g( char const& ) { cout << "char" << endl; } template< class Type > struct Derived: Base { Type t; virtual void g() const override { ::g<Type>( t ); } }; void f( Base& b ) { bg(); } int main() { Derived<int>().g(); } 

As you can, this is also effective, O (1) instead of stupid O ( n ). Also, with checking the type of static (compilation time) instead of checking the type of dynamic time (runtime), saving a rather annoying amount of testing. What more can I say? Indeed, forget about type code and enums and the like. Remember that Bertrand Meyer decided not to support Eiffel enumerations, which is why people tend to abuse them for type codes. Use virtual functions.

Hi virtual features!

They are really useful if you need dynamic type submission otherwise.

So, I recommend using virtual functions for this. :)


EDIT : templatized ::g to avoid possible ambiguities in real code.

-1
source

All Articles