1

I have a type containing some data and I want to loop over the data in the type and dynamically allocate memory in an array based on the data. It's a bit hard to explain exactly what I mean, so some code should help. Here is my best attempt so far:

#include <tuple>

//int wrapper
template<int n>
struct Int{
    static const int value = n;
};

//list of types
template<typename... Ts>
struct MyContainer{
    using Data = std::tuple<Ts...>;
    static const int N = sizeof...(Ts);
    
    template<int n>
    using Nth = typename std::tuple_element<n, Data>::type;
};

//used to allocate memory for MyStruct::array
template<typename DataType>
struct MemoryAllocator{
    template<int i>
    static void exec(char **array){
        using T = typename DataType::Nth<i>;
        const int n = T::value;
        array[i] = new char[n];
    }
};

//template-based "for loop"
struct Looper{
    template<typename DataType, template<typename T> typename Executor, int start, int end, typename... ArgTs>
    static void loop(ArgTs... args...){
        Executor<DataType>::exec<start>(args...);
        if constexpr(start < end){
            loop<DataType, Executor, start+1, end, ArgTs...>(args...);
        }
    }
};

template<typename DataType>
struct MyStruct{
    MyStruct(){
        const int n = DataType::N;
        array = new char*[n];
        Looper::loop<DataType, MemoryAllocator, 0, n-1>(array);
    }

    char **array;
};

int main(){
    using MyDataType = MyContainer<Int<1>, Int<2>, Int<3>>;
    MyStruct<MyDataType> s;
}

I am defining the type MyDataType as a type containing three Ints containing 1, 2, 3. I want to create an instance of MyStruct<MyDataType> and have the constructor of this type initialise a 2D char array, consisting of arrays of length 1, 2, 3. To do this, I tried to create a recursive template to iterate over the three Int types, pull out the underlying ints, and allocate the memory. However, I get the following errors (with g++ 10.1):

main.cpp: In static member function ‘static void Looper::loop(ArgTs ..., ...)’:
main.cpp:34:48: error: expected binary operator before ‘)’ token
   34 |         Executor<DataType>::exec<start>(args...);
      |                                                ^
main.cpp: In instantiation of ‘static void Looper::loop(ArgTs ..., ...) [with DataType = MyContainer<Int<1>, Int<2>, Int<3> >; Executor = MemoryAllocator; int start = 0; int end = 2; ArgTs = {char**}]’:
main.cpp:46:56:   required from ‘MyStruct<DataType>::MyStruct() [with DataType = MyContainer<Int<1>, Int<2>, Int<3> >]’
main.cpp:54:26:   required from here
main.cpp:34:33: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
   34 |         Executor<DataType>::exec<start>(args...);
      |                             ~~~~^~~~~~

Also, I would ideally like to not have to define the MemoryAllocator struct at all and instead use some sort of templated lambda function, but I'm not sure that it's possible, and it's not really a problem if it isn't.

What is the best way to do this?

Ben
  • 470
  • 1
  • 6
  • 18
  • 2
    **tl;dr** of the dupe: `Executor::template exec(args...);` and `typename DataType::template Nth;` - you were missing a `template` keyword on access to those dependent templates. – StoryTeller - Unslander Monica Dec 07 '20 at 13:01
  • 1
    There is also another problem: the declaration of `Looper::loop`: the arguments are `ArgTs... args...`, that is a variadic list of `args` arguments and a following list (the second `...`) of variadic C-style arguments. I don't think is what do you want; I suppose you want only the first variadic list so you have to remove the second `...` – max66 Dec 07 '20 at 13:11

0 Answers0