Board index » cppbuilder » Test a typename?

Test a typename?

Wanted to post this here (with a edits), though I posted it in the
.writing group:

My basic question is this:  is there a way to test for what kind of
typename has been passed in a template function (like testing for what T
is passed in a template function "Foo<typename T>(){...}") and execute a
block of code in the function accordingly?

Here's why it came up:

I want to make a template function that will return the number of values
in a known enum--something that would work like this:

int TmpCount = EnumCount<MyEnumType>();

In concept, I want to do something like this:

enum Foo1Enum {Foo1A, Foo1B, Foo1C, Count_Foo1};
enum Foo2Enum {Foo2A, Foo2B, Foo2C, Foo2D, Count_Foo2};

template <typename TN> int EnumCount()
{
   int RetVal;
   switch (TN) {
      case Foo1Enum: RetVal =  (int)Count_Foo1;  break;
      case Foo2Enum: RetVal =  (int)Count_Foo2;  break;
      default: -1;
   }
   return RetVal;

Quote
}

BUT, of course, you can't use a typename as in "switch(TN)" and you
can't use the names Foo1Enum and Foo2Enum in this manor.

SO, is there a way to test for what kind of typename has been passed in
a template function and execute a block of code accordingly???

Thanks!!!

-Jay

 

Re:Test a typename?


"Jason W. Hinson" <hins...@cna.org> wrote in message
news:3E96D511.1B3DC8C8@cna.org...

Quote
> My basic question is this:  is there a way to test for
> what kind of typename has been passed in a template
> function (like testing for what T is passed in a template
> function "Foo<typename T>(){...}") and execute a
> block of code in the function accordingly?

None that I know of.  Templates are supposed to be tied to the specific data
types passed to them during compile time.  They're not supposed to be smart
enough to differenciate between the data types at runtime.

Quote
> I want to make a template function that will return
> the number of values in a known enum

As an alternative to what you ask, you could wrap each enum in a wrapper
class with a published property, that way the compiler will create RTTI
(runtime type information) for the enum, and then you can use the structures
and methods of TypInfo.hpp to do various operations on the enums at runtime,
such as count the items, iterate through the values one at a time, translate
the items into strings and vice-versa, etc.

For example, I use the following code in my own project:

    #include <typinfo.hpp>
    #include <assert.h>

    #define DECLARE_ENUM_TYPEINFO(e) \
    \
    class e##_HACKED_ENUM_TYPEINFO : public TObject \
    { \
    private: \
        e FTestEnum; \
    __published: \
        __property e eProp = { read = FTestEnum, write = FTestEnum }; \
    public: \
        static PTypeInfo TypeInfo(void) \
        { \
            PTypeInfo ClassTypeInfo; \
            PPropInfo PropertyInfo; \
            PTypeInfo PropertyTypeInfo; \
            \
            ClassTypeInfo = __typeinfo(e##_HACKED_ENUM_TYPEINFO); \
            assert(ClassTypeInfo != 0); \
            \
            PropertyInfo = GetPropInfo(ClassTypeInfo, "eProp"); \
            assert(PropertyInfo != 0); \
            \
            PropertyTypeInfo = *(PropertyInfo->PropType); \
            \
            assert(PropertyTypeInfo != 0); \
            assert(PropertyTypeInfo->Kind == tkEnumeration); \
            return PropertyTypeInfo; \
        } \
        \
        static PTypeData TypeData(void) \
        { \
            return GetTypeData(TypeInfo()); \
        } \
    };

    #define GET_ENUM_TYPEINFO(e) e##_HACKED_ENUM_TYPEINFO::TypeInfo()
    #define GET_ENUM_TYPEDATA(e) e##_HACKED_ENUM_TYPEINFO::TypeData()

With that, you can then do the following:

    DECLARE_ENUM_TYPEINFO(Foo1Enum);
    DECLARE_ENUM_TYPEINFO(Foo2Enum);

    // This line is not neccessary for this particular scenerio,
    // I'm just showing you that you can in general...
    PTypeInfo pTypeInfo = GET_ENUM_TYPEINFO(Foo1Enum);

    PTypeData pTypeData = GET_ENUM_TYPEDATA(Foo1Enum);

    int MinValue = pTypeData->MinValue;
    int MaxValue = (pTypeData->MaxValue/sizeof(pTypeData->NameList));
    etc...

If you wanted to then wrap that into your template class, you could try this
(untested):

    enum Foo1Enum {Foo1A, Foo1B, Foo1C, Count_Foo1};
    DECLARE_ENUM_TYPEINFO(Foo1Enum);

    enum Foo2Enum {Foo2A, Foo2B, Foo2C, Foo2D, Count_Foo2};
    DECLARE_ENUM_TYPEINFO(Foo2Enum);

    template <typename TN> int EnumCount()
    {
        PTypeData pTypeData = GET_ENUM_TYPEDATA(TN);
        int MinValue = pTypeData->MinValue;
        int MaxValue = (pTypeData->MaxValue/sizeof(pTypeData->NameList));
        return (MaxValue - MinValue + 1);
    }

However, do keep in mind that this only works for enums which have
sequential values.  Otherwise, you'll probably have to walk the NameList
manually, counting each item one at a time in a loop instead.

Gambit

Re:Test a typename?


Thanks for the note, Gambit...

I, too, have not found a way to test a typename, so I'm trying a few other
things now to see what gives me the results I like the most.  Your suggestions
will be another welcomed consideration.

-Jay

Re:Test a typename?


"Jason W. Hinson" <hins...@cna.org> wrote in message
news:3E96D511.1B3DC8C8@cna.org...

Quote
> Wanted to post this here (with a edits), though I posted it in the
> .writing group:

> My basic question is this:  is there a way to test for what kind of
> typename has been passed in a template function (like testing for what T
> is passed in a template function "Foo<typename T>(){...}") and execute a
> block of code in the function accordingly?

Please read the thread 'Global Enum Mapping... UGH' is this group.  You can
extend the template I posted there;

  template<typename enumtype>
  class QueryEnumT: public TObject {
  private:
    TTypeInfo* FTypeInfo;
    TPropInfo* FPropInfo;
    TTypeData* FTypeData;
    enumtype FValue;

  public:
    __fastcall QueryEnum(): TObject(),
      // access the RTTI table
      FTypeInfo(reinterpret_cast<TTypeInfo*>(ClassInfo()),
      FPropInfo(GetPropInfo(FTypeInfo,"Value")),
      FTypeData(GetTypeData(FPropInfo->PropType[0]))
    {
    }

    AnsiString __fastcall GetEnumName(enumtype ElementValue) {
      return GetEnumName(FPropInfo->PropType[0],ElementValue);
    }

    enumtype __fastcall GetEnumValue(AnsiString ElementName) {
      return GetEnumValue(FPropInfo-PropType[0],ElementName);
    }

    int __fastcall GetEnumCount() {
       return FTypeData->MaxValue-FTypeData-MinValue;
    }

  __pubished:
    __property enumtype Value={read=FValue,write=FValue};
  };

Then use it in your own template function:

  template <typename TN>
  int EnumCount() {
    std::auto_ptr<QueryEnumT<TN> > p(new QueryEnumT<TN>);
    return p->GetEnumCount();
  }

Ralph

Re:Test a typename?


Hi, Gambit...

Just wanted to let you know, I've been trying out your wrapper idea for
extracting enum type info.  It's got some nice uses, for sure.

There was one thing though: I tested the code below (which you noted as
"untested") and there's a problem.

When the precompiler sees "GET_ENUM_TYPEDATA(TN)", it doesn't know that "TN" is
a typename to be defined when the function is used.  It just sticks in "TN" and
tries to get TN_HACKED_ENUM_TYPEINFO::TypeInfo(), which of course does not
exist.

Ah well.  If only you could put published members in a template class.  Then,
as  Ralph Kazemier noted, a template class could act as the wrapper, and, if I
wanted, I could then make a template function that creates an instance of the
appropriate template class and counts the enums.

In any case, thanks for the info.

-Jay

p.s.  As a work around that keeps you from having to remember to add an extra
"MyEnum_Count" at the end of an enum for counting, I did try adding the
following to the bottom of  the #define DECLARE_ENUM_TYPEINFO(e) section:

\
int e##_Count() \

Quote
} \

    PTypeData pTypeData = e##_QUERY_ENUM_TYPEINFO::TypeData(); \
    int MinValue = pTypeData->MinValue; \
    int MaxValue = pTypeData->MaxValue; \
    return (MaxValue - MinValue + 1);   \

Quote
}

so MyEnum_Count() returns the number of values in a sequential enum.  I also
added

AnsiString EnumToName(e Value)                                 \
{                                                              \
    PTypeInfo pTypeInfo = e##_QUERY_ENUM_TYPEINFO::TypeInfo(); \
    AnsiString Answer = GetEnumName(pTypeInfo,Value);          \
    return Answer;                                             \

Quote
};                                                             \

for the fun of it, which creates a set of overloaded functions to return the
EnumName.

Anyway, thanks again.

Quote
"Remy Lebeau (TeamB)" wrote:
> ...
> If you wanted to then wrap that into your template class, you could try this
> (untested):

>     enum Foo1Enum {Foo1A, Foo1B, Foo1C, Count_Foo1};
>     DECLARE_ENUM_TYPEINFO(Foo1Enum);

>     enum Foo2Enum {Foo2A, Foo2B, Foo2C, Foo2D, Count_Foo2};
>     DECLARE_ENUM_TYPEINFO(Foo2Enum);

>     template <typename TN> int EnumCount()
>     {
>         PTypeData pTypeData = GET_ENUM_TYPEDATA(TN);
>         int MinValue = pTypeData->MinValue;
>         int MaxValue = (pTypeData->MaxValue/sizeof(pTypeData->NameList));
>         return (MaxValue - MinValue + 1);
>     }

> However, do keep in mind that this only works for enums which have
> sequential values.  ...

Re:Test a typename?


"Jason W. Hinson" <hins...@cna.org> wrote in message
news:3EA86499.8CE0CB2@cna.org...
<snip>

Quote
> Ah well.  If only you could put published members in a template class.
Then,
> as  Ralph Kazemier noted, a template class could act as the wrapper, and,
if I
> wanted, I could then make a template function that creates an instance of
the
> appropriate template class and counts the enums.

Yep, it's really too bad that one can't publish a templatized member :-(.  I
never tested the code before I posted it and I truly am sorry for pointing
you in the wrong direction.

Ralph

Other Threads