I am developing a framework to simplify creation of embedded software applications.
Resources are typically limited in this type of environment, so I need to make it very efficient in its use of memory space.
One goal is to be able to reference any variable by a <typeNumber, instanceNumber> value pair.
I have no problem creating objects that support an abstract list of instances of any given type.
I can successfully use operator[] to access any instance with its type-specific behavior.
I can likewise make an abstract list of of those objects that support type instance lists.
However, it is is a 2-step process to access the data and its type-specific behavior.
It seems that whatever I try, I ultimately come to a single function call that must return any type. It seems that C++ does not support this.
I suspect that RTTI might solve my problem, but I am trying to avoid using it, because I'd like my framework to work in systems that do not support it. (Actually, some say they support RTTI, but do not support exception handling, which RTTI uses.)
I'd also like to avoid any type of hard-coded switch block with fixed type-casting because I'd like to be able to add types to the list dynamically
Can anyone suggest an alternative?

Recommended Answers

All 12 Replies

If you work with Microsoft compilers and do any COM programming (such as for distributed processing and inter-language support) you will come across the VARIANT structure with is nothing more than a structure with two objects:

  • unsigned int type -- declares the type of data contained in the structure
  • union -- a uniion of a lot of different data objects, such as char, short, long, char*, etc

win32 api has several functions that work on the VARIANT structure, and there is a _variant_t c++ class that wraps the VARIANT and some functions.

As for your question, yes under some circumstances a function can return a VARIANT or _variant_t object.

#include <windows.h>
VARIANT foo()
{
    VARIANT vt;
    VariantInit(&vt);
    return vt;
}

http://www.boost.org/doc/html/any.html
http://www.boost.org/doc/html/variant.html

you may also find this discussion on static typing technology at large interesting.
http://groups.google.com/group/comp.std.c++/browse_thread/thread/da71464ad690d506/303e3bf2407a7609?lnk=st&q=min+max+c%2B%2B+#303e3bf2407a7609

You just might have pointed me in a useful direction, but I'll need a little more time to evaluate whether the "any" or "variant" definitions will work for my purpose.
I hope to spend some more time on this project over the coming weekend.

I read through the discussion thread and found it quite entertaining.
Thanks much for you assistance.
I will try to report back on the results.

If you work with Microsoft compilers and do any COM programming (such as for distributed processing and inter-language support) you will come across the VARIANT structure with is nothing more than a structure with two objects:

  • unsigned int type -- declares the type of data contained in the structure
  • union -- a union of a lot of different data objects, such as char, short, long, char*, etc

win32 api has several functions that work on the VARIANT structure, and there is a _variant_t c++ class that wraps the VARIANT and some functions.

As for your question, yes under some circumstances a function can return a VARIANT or _variant_t object.

#include <windows.h>
VARIANT foo()
{
    VARIANT vt;
    VariantInit(&vt);
    return vt;
}

I can't say that I've done any COM programming, but years ago I made it about a third of the way through a book titled "Inside COM". From what little I learned about it (and vaguely recall), it has some parallels to the framework that I'm attempting to construct. At least, I'm trying to create a common, open interface to all applications built with my framework.

Life is much different in the embedded systems world from the IT / PC world.
The first thing that comes to mind for me when I think of a Microsoft VARIANT type is a bloated and cumbersome component of the Visual Basic world. I must admit that MS has made big strides over the last decade or so with improvements to their whole family of languages. But, I digress...

I definitely cannot afford to turn all my variables into VARIANT types. A union of all types takes the storage space of the largest type. That is far too wasteful.
However, some of the other concepts I'm looking at lead me to believe that it might be possible to use it as a temporary, intermediate value on the stack.

But, I have not yet lost all hope of finding a more elegant solution.
Thanks for the suggestion.
If I'm misunderstanding or missing something important, please don't hesitate to point it out to me.

I have spent some time looking at the ANY and VARIANT classes in the Boost libraries. I'm still far from a complete understanding, but I don't think that they solve my problem.

I seems that I need to perform a run-time cast to a type that is specified by an integer. Ideally, the integer comes from a dynamic list of types, that is created by appending "plain old data" (POD) types and derived types. But, I can live with a fixed enumeration of types. (e.g. 1 = char, 2 = int, 3 = long, 4 = myType, ... etc.

In any case, I ultimately come down to a need to downcast a base pointer to a derived type, using a number to identify the type. Or, I could cast a void pointer ( or a char pointer, if it helps ) to the identified type.

I understand that RTTI could help me, but only if I loop through the list of types to find the correct one. ( If there is a cast_to_type_of_TypeID, please let me know. ) However, the target of my project is embedded controllers and I am concerned about the overhead of RTTI. If RTTI could actually do such a cast, I would prefer to simply adapt the method and minimize the overhead.

I expect to make use of templates, but not the STL. Both the STL and RTTI make use of exception handling. I cannot use this in my system as it is generally not supported by compilers for embedded processors ( with good reason ).

For an example, assume I have a class that contains the data < typNum, dataAddr > where typNum is an integer and dataAddr is the address of a data value that matches the specified type.
Using instances of this class, I'd like to write:
A = B * C; // Or, perform other operations.
- or -
f(A) = f(B) * f(C); // f() is some conversion operator.

It seems that any operator ( function, macro, other? ) that I apply to B or C can potentially perform the correct cast within the function, but it cannot return it. So, back at the ( B * C ) level, nothing is gained.

The Boost ANY class seems to work fine for assignments from one ANY to another. But, it doesn't do anything to help other operations.

Unless you have any other suggestions, I need to start a re-design effort.
Reid

what compiler are you using and what operating system are you working with. I know for a fact that Microsoft added exception handling in eVC++ 4.0 which is pretty old now.

>>I definitely cannot afford to turn all my variables into VARIANT types. A union of all types takes the storage space of the largest type. That is far too wasteful.


cout << "sizeof(VAIRIANT) = " << sizeof(VARIANT) << "\n";

The result of the above is 16. If you can not afford 16 bytes then you do have a very difficult time ahead of you.

This is for embedded programming. Think of the micros in your car that control the engine or provide cruise control.

My first target ( for testing ) is a TI DSP processor that uses a proprietary compiler from TI. Their IDE is called Code Composer Studio.

There is no operating system to speak of. We use the term "kernel" to refer to the equivalent code that provides the hardware interface and calls the application process, which executes repeatedly every millisecond or so.

Typically, there is only 2000 bytes of non-volatile memory space for configuration parameters.

The minimum variable size is 16 bits, so I might use bitfields to provide 8-bit values.

So yes, 16 bits is a lot. However, none of this matters to my question.

My initial question about a variant return type was not about a function that returns a type named VARIANT. It was about a function that could return any of several types.

If I create a function in a derived class that overrides a function of the same name in the base class, and change the return type of the function, the compiler complaints about a "variant return type".

I assume that the VARIANT type you mention is implemented as a union of types. The size of this union is the size of the largest type in the union.

Let me try this question:
Given:
enum { typChr, typInt, typLng } typeID;
typedef union
{
char charVal;
int intVal;
long longVal;
} VARIANT;

long val;
void *pVal = &val;

At run-time, I know that pVal points to memory that holds a long value, because it has an associated TypID that equals typLng.
With this information, how do I cast pVal to a long pointer?

Or, assume I cast pVal to a variant:
VARIANT *pVar = VARIANT *(pVal);
then how do I select pVar->longVal?

I'm beginning to think that I have to create all the standard operator functions for a custom VARIANT type that can accommodate any type of contained values, based upon the typeID.

This is not something that is easily modified to add another value type.
Any more suggestions?

Thanks,
Reid

you use VARIANT just as you would any other structure.

VARIANT foo()
{
    VARIANT vt;
    vt.vt = VT_I4; // long integer
    vt.llVal = 123;
    return vt;
}

int main()
{
    VARIANT Var = foo();
    cout << "type = " << Var.vt << 
        " long value = " << Var.llVal);

    // or if you don't know the type of variant
    switch(Var.vt)
    {
    case VT_I2: cout << "integer"; break;
    case VT_L4: cout << "long"; break;
        // etc
    }
    return 0;
}

>>My initial question about a variant return type was not about a function that returns a type named VARIANT. It was about a function that could return any of several types.

That is not possible in C or C++ without using a structure or class. The AnyType class in Boost or something like VARIANT structure are the only two ways to achieve your design. You could use c++ templates but if you can't afford 16 bytes for VARIANT then you can afford the duplication that templates will create, which is a great deal more than 16 bytes.

Thanks for your continued patience.
In my world, code space and data space are very different things. My code space is not as limited. Also, my intended use of templates is limited.

I initially created a template for a class that manages a set of values of a given type. It uses an operator [] function to return a reference to any value in the set, by instance number. I can then create an "instance manager" for any type. This is really nice, because the reference can be used as an l-value or an r-value.

I wanted to do the same thing with a a class that manages a set of "instance managers". That's when I ran into trouble. In order to put the "instance managers" into a set ( collection, pseudo-array, whatever...), I had to up-cast them to base pointers. That's where I lost the static type identification.

I have since realized that, given this problem, I can just as well use a single "instance manager" that simply manages a set of void pointers to data instances of a specific size. Since I have to do a cast anyway, I might as well do it "outside" the "instance manager".

The "void pointer instance manager" concept is also pretty much how I intend to manage the memory heap anyway, so I may be able to consolidate this code and save even more space.

I have considered that all of my "instance managers" could be in a list that is a static member of my base class. That would make them available to a base object without down-casting. But, I prefer to also make the type ID a static member of each derived class, so that wouldn't be available.

I further considered that it might be possible to design the classes so that the most derived object contains only a type number and instance number, with all data higher in the class hierarchy containing only static data, such as a pointer to a list.

In the big picture, there is only one instance of each "parameter value", but there can be many <type number, instance number> references that can be placed into a hierarchical data structure.

There is much more to the full concept, but it includes provision of a standardized interface for all applications and the ability to manage data the same within a micro and between micros on a network.

I understand that I am taking a very unconventional approach and C++ might not be the best language, but it has advantages over C, even if I don't use most of them. It is also available for many embedded processors now, while few other languages are supported.

I appreciate any additional comments you care to share.

>> I have since realized that, given this problem, I can just as well use a single "instance manager" that simply manages a set of void pointers to data instances of a specific size. Since I have to do a cast anyway, I might as well do it "outside" the "instance manager".

>> The "void pointer instance manager" concept is also pretty much how I intend to manage the memory heap anyway, so I may be able to consolidate this code and save even more space.

>> I have considered that all of my "instance managers" could be in a list that is a static member of my base class. That would make them available to a base object without down-casting. But, I prefer to also make the type ID a static member of each derived class, so that wouldn't be available.

i'm not absolutely certain about what you are driving at; but would using an exemplar pattern be a solution to this problem?

the instance_manager_base class

// **** instance_manager_base.h ****
struct instance_manager_base
{
  static instance_manager_base* 
       get_instance_manager_for_type( int type_number ) ;
  virtual int type_number() const = 0 ;
  virtual ~instance_manager_base() ;
  // virtual other methods = 0 ;
  protected: instance_manager_base() ;
  private: instance_manager_base* This() { return this ; }   
};

an example of using the instance_manager_base

// **** test_it.cc ****
#include "instance_manager_base.h"
#include <iostream>
int main()
{
  instance_manager_base* mgr = 0 ;
  mgr = instance_manager_base::get_instance_manager_for_type(101) ;
  std::cout << mgr << '\n' ;
  mgr = instance_manager_base::get_instance_manager_for_type(999) ;
  std::cout << mgr << '\n' ;
}

the base class implementation

// **** instance_manager_base.cc ****
#include "instance_manager_base.h"
#include <vector>
namespace
{
  std::vector<instance_manager_base*> _instance_managers ;	
}

instance_manager_base::instance_manager_base()
{ _instance_managers.push_back( This() ) ; }

instance_manager_base* 
  instance_manager_base::get_instance_manager_for_type( int type_number )
{
  for( size_t i=0 ; i < _instance_managers.size() ; ++i )
  {
    instance_manager_base* mgr = _instance_managers[i] ;
    if( mgr->type_number() == type_number ) return mgr ;
  }
  return 0 ; // not found
}

instance_manager_base::~instance_manager_base() {}

a typical derived class instance manager (no header, only impl)

// **** instance_manager_101.cc ****
#include "instance_manager_base.h"
namespace
{
  struct instance_manager_101 : instance_manager_base
  {
    enum { type_id = 101 } ; // equivalent to static member
    virtual int type_number() const { return type_id ; }
    static instance_manager_101 exemplar ;
    // override other methods
  };
  instance_manager_101 instance_manager_101::exemplar ;
}

Ancient Dragon and vijayan121,
I really appreciate your efforts to help me with my question.
I hope you've either found it interesting, or you're getting paid to do this.

The full extent of what I'm trying to do is just too massive to communicate in this forum.
During the course of this conversation, I have continued to study this issue on my own.
Your answers, and a lot of web browsing, have helped me understand several concepts.

I think I can conclude that what I was trying to do is not possible, in the compact and efficient form that I was seeking.

However, there are clearly several ways to skin this cat, so I will continue to chip away at it.

I'm not sure how this forum works, but it appears that you get credit for solving issues.
So, please, mark this one solved and take your points.
Thanks much for your generous efforts.
NorseMN

>>I hope you've either found it interesting, or you're getting paid to do this.
Interesting, yes. Getting paid, no.

>>there are clearly several ways to skin this cat
For those who don't know, skin a cat doesn't mean an animal. A cat refers to a Catapiller heavy duty dirt moving equipment. My dad did that for about 50 years and I heard that phrase thousands of times. Catapiller is a brand name of the equipment.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.