1

Sorry I am new both to the community and c++, please be gentle.

To begin with, as this is to run on a microcontroller, memory and compiled code space are extremely valuable.

I have a requirement to take input from various sources and feed them into a central processing function. The rolled up parameters fed in are to be named, be of varying types and, allow for type checking, so they can be compared against criteria unknown at compile time. I have borrowed bits of code from here and there and come up with the following.

template <typename T_ty> struct TypeInfo { static const char * name; };
template <typename T_ty> const char * TypeInfo<T_ty>::name = "unknown";

#define MAKE_TYPE_INFO( type )  template <> const char* TypeInfo<type>::name= #type;

// Type-specific implementations.
MAKE_TYPE_INFO( int );
MAKE_TYPE_INFO( float );
MAKE_TYPE_INFO( String );
MAKE_TYPE_INFO( char * );
MAKE_TYPE_INFO( bool );

class ParaBase
{
public:
  char*   _type ;
  char*   _name;
  void*   _child;

  const char* name()  { return _name; }

  ParaBase(){}

  ParaBase(const char* name, const char* type, const void * child )
    :
    _name( (char*) name ),
    _type( (char*) type ),
    _child( (void*) child ) {}


  template <class U>
  bool is()
  {
    return ( TypeInfo<U>::name == _type );
  }

};

template <class T>
class Para : public ParaBase
{

  T _value;

public:

    Para( const char* name,  const T value )
    :
     ParaBase( name,  TypeInfo<T>::name, this ),
     _value( value )
    {}

    Para( ParaBase& paraBase )
        :
        ParaBase( paraBase._name,  paraBase._type, this )
    {}


  operator T()  { return _value; }

  const T value() { return _value; }

    template <class U>
    U as()
    {
        return *( ( U *)  _value );
    }


};

To test it I do the following:-

ParaBase para[3];

para[0] = Para<char*>("Param-one", "Hi");
para[1] = Para<bool> ("Param-two", true);
para[2] = Para<float>("Param-three", 2.05);

I can feed para into a central function fine.

bool ok = para[1].is<bool>(); // is true
bool notok = para[1].is<char*>(); // is false

So type checking works, yeah!

Para<char*> testDownCast =  ( Para<char*>)  para[0] ;
char* orig = testDownCast.as<char*>();

Erm, not so good. Major fail here. My testDownCast pointer (if I am using the correct term) just contains junk. What am I doing wrong?

Any help would be gratefully received. Thanks in advance for helping a novice.

user7296390
  • 160
  • 7
  • You might want to read [What is object slicing?](http://stackoverflow.com/questions/274626/what-is-object-slicing) – Bo Persson Dec 14 '16 at 13:11
  • Welcome to [object slicing](http://stackoverflow.com/questions/274626/what-is-object-slicing). You need an array of *pointers* for your idea to work. – n. m. could be an AI Dec 14 '16 at 13:16
  • Thanks for the tips. Still struggling to get my head around a working solution. Not sure if I am approaching the problem in the right way. – user7296390 Dec 14 '16 at 15:10

1 Answers1

0

Your problem lies here:

ParaBase para[3];
para[0] = Para<char*>("Param-one", "Hi");

You assign Para object to ParaBase object. As ParaBase object is base object, it will not contain any information that is specific to derived object (Para). In this case,

 T _value;

from Para object is lost. Then you assign back ParaBase object to Para object:

Para<char*> testDownCast =  ( Para<char*>)  para[0] ;

It's correct, but para[0] object does not contain any information about _value, so it cannot be copied back to testDownCast.

To make your example work, you should change array of ParaBase

ParaBase para[3];

to array of ParaBase pointers

ParaBase* para[3];
Para<char*> realPara0("Param-one", "Hi");

para[0] = (ParaBase*)&realPara0; //Or use C++-style cast here

Of course in this case you will not have ParaBase objects, only pointers to them. But you can cast back to Para object. You have to adjust rest of your code of course.

By the way - it's not good low-footprint microcontroller code. For each tempate type you use, new code will be generated. Also copying objects each time will cause your stack to grow (not a problem until you have small objects). 'Classic' microcontroller implementation would rely on union, and maybe additional information about type passed through union.

I'm not telling not to use C++ in microcontrollers (I'm great fan of this!), but this should be done with awareness. Here is great article (two parts) of using C++ in embedded systems: http://www.embedded.com/design/programming-languages-and-tools/4438660/1/Modern-C--in-embedded-systems---Part-1--Myth-and-Reality

Mazi
  • 182
  • 8