0

I want to do something like this:

template<typename CType, unsigned int targetDimensions> struct GeneratePointerType
{
    typedef typename GeneratePointerType<CType, targetDimensions-1>::type* type;
    static const unsigned int dimensions = GeneratePointerType<CType, targetDimensions-1>::dimensions+1;
};
template<typename CType> struct GeneratePointerType<CType, 0>
{
    typedef CType type;
    static const unsigned int dimensions = 0;
};

Dictionary<int, GeneratePointerType<int, valueDimensions>::type >

So basically I want to instantiate a container template for a pointer type, but I don't know the pointer level of the pointer to create before runtime, so the approach from above of course can't wocompile, as "dimensions" isn't a compile-time constant.

Is there a way (that is compatible to pure C++03 without any C++11 only features) to achieve the intended behavior?

EDIT: "If you could tell us the real problem, we might have a better solution." "So to clarify, you want a map of N dimensional array/objects, where N is a runtime value? Wierd. I can't imagine a use-case" OK, let me tell you a few words about the usecase:

I have a class Template Dictionary, which is basically just behaving like the C# or Java Dictionary generics.

This class is used in C++ wrapper library around a C library.

Therefor I have conversion functions, that convert data between instances of C++ container classes and instances of C container structs.

As you know, C doesn't have generics, so while in C++ I can create containers like this:

Dictionary<int, int**> dict;

in C I have to do it like this:

CDictionary dic;
dic.keytype = TYPECODE_INT;
dic.valuetype = TYPECODE_INT;
dic.valueDimensions = 2;

Now when converting a C Dictionary into a C++ Dictionary, I struggle on how to generate the correct number of *'s, as the info stored inside the C dictionary isn't a compile time constant.

EDIT2: Actually the point, that I am getting that runtime-dimension-counts from the underlying C interface doesn't matter, as the C lib creates those structs from serialized data, that comes in over the network and as its impossible to know at compiletime of the lib, how many array-dimensions an array, that comes in over the network from another app in potentially another programming langauge, will have, a C++ implementation of the deserialization would still have to determine valuetypes for Dictionaries from runtime information about the array dimensions.

EDIT3: "OK, I think you need to illustrate how you want to use this structure, because I clearly didn't interpret your question correctly, and none of this information is in the question. Can you edit in some pseudocode showing what you're trying to achieve?" call to public interface:

Dictionary<int, int*> dic;
int* arr = new int[10];
dic.put(1, arr, a0);
delete arr;

send(dic); // dic gets serialized and sent over the netwowork

When receiving a serialized dic, I want to do deserialize it back, before passing it to a callback:

// read out typecodes and dimnesions from the serialized data
// [...]
// create the Dictionary from that info
switch(valueTypeCode)
{
    case TYPECODE_SHORT:
        return new Dictionary<int, GeneratePointerType<short, valueDimensions>::type>[size]();
    case TYPECODE_INTEGER:
        return new Dictionary<int, GeneratePointerType<int, valueDimensions>::type>[size]();
}
// fill it with the deserialized payload afterwards
// [...]
Kaiserludi
  • 2,434
  • 2
  • 23
  • 41
  • Why do you have the `dimensions` member defined that way, since it's always exactly the same as `targetDimensions`? – Mooing Duck Aug 01 '12 at 16:18
  • 2
    I strongly believe you don't want this. This sounds a lot like you're trying a misguided solution to another problem you didn't mention. If you could tell us the real problem, we might have a better solution. – R. Martinho Fernandes Aug 01 '12 at 16:18
  • So to clarify, you want a map of `N` dimensional array/objects, where `N` is a _runtime_ value? Wierd. I can't imagine a use-case. – Mooing Duck Aug 01 '12 at 16:20

1 Answers1

0

If the parameter N isn't known at compile time, you can't make it part of your static type. So, you definitely have to use some kind of runtime dispatch.

Likely options are:

  1. just wrap the C structures shallowly (providing operator overloads and other methods, encapsulating the underlying data) and access it exactly the same way

    class Dictionary {
        CDictionary *inner;
    public:
        // C++ syntactic sugar here
    };
    
  2. if N is bounded above by some reasonable value (eg, you can assume N < 10), you could instantiate a template class for every valid N, which implements an abstract interface. Then your template instantiations are hidden in a translation unit which only exposes a public (virtual) interface and a factory function; actual access uses runtime polymorphism

    class AbstractDictionary {
    public:
        virtual ~AbstractDictionary() = 0;
        // virtual methods
    };
    AbstractDictionary* wrap(CDictionary *);
    
Useless
  • 64,155
  • 6
  • 88
  • 132
  • to 1.: I am not sure, how wrapping up the C structs should solve that problem. to 2.: Well, in theory I can only assume N<=UINT_MAX, which doesn't look like a resonable amount of specializations to me. In practice N will most of the time be relatively small, as N is the number of dimensions of a value, that is allowed to be a multidimensional array. So 0 (no array) and 1 (single-dimensional) are very common, 2 and 3 are still common, it will get more rare the higher N gets, but if don't use a real high max value for N I can swear, that it will be to low for some users - you know, Murphy's law – Kaiserludi Aug 01 '12 at 17:16
  • _I am not sure, how wrapping up the C structs should solve that problem_ ... well, you haven't told us _what the problem is_. Presumably the C lib works fine already, so what do you hope to gain? – Useless Aug 01 '12 at 17:33
  • The C lib interface suffers from limitations of C as a programming language – Kaiserludi Aug 01 '12 at 17:44
  • In C++ one can just create a container like this: Dictionary and in the will only accept int as keys and int** as values. In C one can specify the amount of* in the type, but then still sore something different. Also one can do something like this dic.put(key, valObject_create(&myString, TYPECODE_INT)). The C++ interface uses features like templates to save the user from accidentally passsing incompatible stuff, by being much more typesafe. – Kaiserludi Aug 01 '12 at 17:55
  • C++'s stronger type-safety doesn't really work if you don't know the type at compile time. I'm not sure casting `int ****` to `int **` is strictly legal even in C, but if that's what you want, can't you just use a C-style cast? – Useless Aug 01 '12 at 19:59
  • Yes, I could, but I would still know to what I would have to cast it. I thought, that there could maybe be a better solution then a giant switch over the dimensions and then doing somehting like case 1: (int*); case 2: (int**); case 3: int***; and so on, as such a switch would mean, that I would have to stop at some level. – Kaiserludi Aug 01 '12 at 20:28
  • OK, I think you need to illustrate how you want to _use_ this structure, because I clearly didn't interpret your question correctly, and none of this information is in the question. Can you edit in some pseudocode showing what you're trying to achieve? – Useless Aug 02 '12 at 10:41