0

Have some template classes defined as follows:

template <typename T>
class Data {
   [...]
};

In some other classes, I need to both use a type and a corresponding integer ID, as defined by the Python numpy C API.

E.g. the numpy API defines types such as npy_bool which correspond to constants such as NPY_BOOL, for all base types.

The issue is that even though values NPY_BOOL, NPY_INT etc are all different, the corresponding types are not. npy_bool and npy_uint8 are both aliases of unsigned char, but are interpreted differently by the numpy down the road.

I want to derive some template classes working on different types where the corresponding ID is also available to the class methods.

I tried to use trait classes mapping types to IDs, e.g.

template <typename T> struct Type  { static const int Id  = 0;         };
template <> struct Type<npy_bool>  { static const int Id  = NPY_BOOL;  };
template <> struct Type<npy_uint8> { static const int Id  = NPY_UINT8; };
[...]

but the complier rejects these template definitions as the types npy_bool and npy_uint8 are actually both unsigned char.

I then tried the opposing traits mapping an integer ID to a corresponding base type:

template <int ID> struct Type      { typedef int       C; };
template <> struct Type<NPY_BOOL>  { typedef npy_bool  C; };
template <> struct Type<NPY_UINT8> { typedef npy_uint8 C; };
[...]

The templates describing the reverse mapping are now accepted by the compiler, but when I try to use them in further template definitions, such as:

template <int ID>
class DataPython: public Data<Type<ID>::C> {
   [...]
};

this is rejected flatly by the compiler. g++ complains that it "expected a type, got Type<ID>::C".

I can imagine solutions such as

  • providing the type IDs separately, with some runtime verification that the numerical ID and the base type are compatible.
  • encapsulating the base types the compiler considers to be identical in different classes in order differentiate them, at the expense of losing the underlying semantics (operators, etc.).

but neither looks very elegant. Surely there must be a better way.

Chris
  • 387
  • 1
  • 8
  • 1
    `class DataPython: public Data::C>` – Sam Varshavchik May 25 '20 at 18:38
  • Wow that was a quick and efficient response. Thanks! Would you mind explaining why in this particular instance typename must be explicitly given? I fail to grasp the reason, knowing that the template definition of Data takes a typename parameter? Just curious ... – Chris May 25 '20 at 18:46
  • 1
    Even if `const char *p` is a `const char *`, trying to assign an `int` to it results in a compilation error. Similarly, in a template declaration, dependent identifiers are presumed to be class members, instead of class types, and `typename` changes the default. See the question that I linked to this one, for more information. – Sam Varshavchik May 25 '20 at 18:58

0 Answers0