0

I've checked posts here that I can use template for nested struct. But when I'm trying to initialize an array inside a nested struct, there seems problem during initialization. In the following example, the array size is one of the parameters of the nested struct so Visual Studio complained that the array size is illegal. Here is the definition:

//template<typename U, typename T>
template<typename U, size_t T>   // this line also not work
struct A {
    struct B {
        struct C {
            vector<U> count[T];    // count needs to have variable size 
            C() {        
                count = new U[T];  // allocate size. Not work
            }
        C c;
    };
    B b;
};

Did I do anything wrong when using the template and initialize the array?

Thanks

visitor99999
  • 163
  • 1
  • 10
  • 1
    You are declaring `count` as an array, then trying to initialize it with a pointer. This is not valid. you can reproduce this by doing `int x[5]; x = new int[5];` and get the same error. What exactly are you trying to do? Should the array size be fixed? Or dynamic? – ChrisMM May 16 '22 at 17:23
  • For the moment, get rid of the nesting. Figure out how to get that declaration to work in a less complicated context. Hint: `count[T]` attempts to use the name of a type `T` as the size of an array. – Pete Becker May 16 '22 at 17:23
  • oh, i see. array size should be dynamic, related to the T variable – visitor99999 May 16 '22 at 17:24
  • I suggest you invest in [some good C++ books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282). – Some programmer dude May 16 '22 at 17:27
  • Is `count` a C array or a `vector`? It is defined as one and initialized as the other. There would also be `std::array` as option. – Sebastian May 16 '22 at 17:37
  • @Sebastian count is a vector. I've changed "typename T" to "unsigned T" or "size_t T", still has like "array is not assignable". If not using T variable and fix vector size like "vector count[5]", the above code works just fine. But the vector size needs to be a variable. – visitor99999 May 16 '22 at 17:41
  • `C c;` inside `C`? how is that going to work? – Ted Lyngmo May 16 '22 at 17:47
  • @visitor99999 What was your intention when you wrote: `count = new U[T];`. Were you trying to create a vector `count` with elements of type `U` with size `T`? – Jason May 16 '22 at 17:47
  • @AnoopRana yes, it is intended to have count with elements of type U and size of T. – visitor99999 May 16 '22 at 17:49
  • 1
    `vector count[T]` is a C-style array of (vectors of Us) with size T. I'm pretty sure you should have `std::array` there and then you don't need a constructor. – Goswin von Brederlow May 16 '22 at 17:50
  • If the size of `count` is supplied via a template parameter, can't you just make it a `std::array` like [this](https://godbolt.org/z/796E5PWaY)? – Ted Lyngmo May 16 '22 at 17:51
  • @visitor99999 If that's the case, refer to my answer below i have written how to do that. – Jason May 16 '22 at 17:53
  • Correct me if I'm wrong, but using a C-style array or `std::array`, `count` is not going to be _variable_ in size. It's size will just be set via a template parameter at compile time. – Chris May 16 '22 at 17:58
  • @TedLyngmo yes, both std::array and vector approach worked. I just tested it. Thanks. I think since C() is constructed, so "C c" and "B b" can be used, like you showed in your code piece. I don't understand why Anoop's solution (basically the same as yours) would take out "C c" and "B b" lines. – visitor99999 May 16 '22 at 18:17
  • @visitor99999 Hmm without the `C c;` and `B b;` lines `A` will be empty. – Ted Lyngmo May 16 '22 at 18:20

2 Answers2

1

There are 3 problems with your current code.

Problem 1

You're missing the closing braces and semicolon }; corresponding to the struct A. To solve this just add }; corresponding to struct A as shown below.

Problem 2

T is a template type parameter and hence cannot be used to specify the size of an array. The simplest way of solving this is make T as template nontype parameter as shown below.

Problem 3

count is an array of vectors in your example so count = new U[T]; doesn't make sense. Looking at your comment, you were trying to create count as a vector with elements of type U and size T which can be done as shown below.

Additionally, note that we can't have C c; inside class type C and similarly we can't have B b; inside B. This is because we cannot have a non-static data member of incomplete type inside a class.


Solution

//-------------------vvvvvvvvvvv---->nontype parameter
template<typename U, std::size_t T>
struct A {
    struct B {
        struct C {
            std::vector<U> count; //count is a std::vector    
            C(): count(T) {        
                  std::cout<<"size of count vector is: "<<count.size()<<std::endl;
            }
        //C c;//this won't work here as C is INCOMPLETE at this point
        };//--------->C is complete after this point 
        
        C c; //THIS WORKS HERE because C is COMPLETE at this point
       // B b;//this wont work here as B is INCOMPLETE at this point
    };//------------->B is complete after this point

    B b; //THIS WORKS HERE because B is INCOMPLETE at this point 
};//added this  

Working demo

Jason
  • 36,170
  • 5
  • 26
  • 60
  • This will not work with the definition of `count`, with `count = new U[T]` – ChrisMM May 16 '22 at 17:31
  • @Anoop why need to take out "C c" and "B b" lines? Your solution seems same as Ted's. – visitor99999 May 16 '22 at 18:18
  • @visitor99999 See in my updated/edited answer at which point we can have `C c;` and `B b;`. In particular, we can have `C c;` after `C` is complete similarly we can have `B b;` after `B` is complete. I have written some comments in my answer so that you can see at what point `C` and `B` become complete and after that we can use `C c;` and `B b;` as i have done in my updated answer. That is, you can use `C c;` after the `};` of struct `C` and similarly you can use `B b;` after its corresponding `};`. – Jason May 16 '22 at 18:25
  • @AnoopRana I see. Now I see I actually misplaced the ";" in my original post. Yes, B and C were incomplete because of the ";". Both yours and Ted's solution would work. I will just upvote both of them, if it's allowed. Thanks. – visitor99999 May 16 '22 at 18:32
0

Did I do anything wrong when using the template and initialize the array?

Yes, you do count = new U[T];, but count is not a pointer.

If you want the vector to be initialized to have the size T, provide T to the vector's constructor in the member initializer list:

template<typename U, size_t T>
struct A {
    struct B {
        struct C {
            std::vector<U> count;
            C() : count(T) {}  // now `count´ is constructed with `T` elements
        };                     // <- you are also missing this line
        C c;
    };
    B b;
};

If you really want a fixed size array of T vector<U>s:

#include <array>
template<typename U, size_t T>
struct A {
    struct B {
        struct C {
            std::array<std::vector<U>, T> count;
        };
        C c;
    };
    B b;
};
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108