2

I wish to use structures to create a datatype which contains other references of an array of the structure itself OR structures of another type. Using templates will obviously result in an infinite declaration of the type itself when the reference is of same generic type. My current solution is to explicitly declare another struct type and the struct type of itself. I was wondering if there was a more clever solution (using structs).

struct Transform
{
    float x;
    float y;
    float z;
    float qx;
    float qy;
    float qz;
    float qw;
};

struct Pattern
{
    enum type{ linear, rectangular, circular };
    char name[20];
    int id;
    Transform t[PATTERN_SIZE];
};

struct Group
{
    enum type{ pattern, group };
    char name[20;
    int id;
    Group *g[20];
    Pattern *p[20];
};
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Ruptr
  • 45
  • 4
  • No it is not a duplicate of that question. I am asking if it is possible to have a variable within the struct be of either type itself or type pattern. – Ruptr May 20 '19 at 11:05
  • 1
    Ok, you question is worded weirdly. Then what you are looking for is std::variant (or boost::variant or similar if you are on older compiler). – Dan M. May 20 '19 at 11:08
  • 2
    Your question is quite poorly worded. Could you explain what problem are you trying to solve? It look like [XY problem](https://meta.stackexchange.com/q/66377/455871) as posted. – Daniel Langr May 20 '19 at 11:41
  • How do you mean that the union is wasteful? If the code path ever needs an A it must have room for an A, so unless your normal path is B and B is significantly smaller, any polymorphic scheme that includes an allocation operation and/or a pointer is likely to be overall more "wasteful", especially when you do need an A. – Gem Taylor May 20 '19 at 15:45
  • @GemTaylor You might be right. I guess it is sort of a case of early over-optimization, but I am not too familiar with C++ yet, so I guess I am just trying figure out the possibilities of the language. Anyway, thanks for the comments. P.S. apologies for the poorly worded question :/ – Ruptr May 20 '19 at 20:52

2 Answers2

1

It is really C-ish, but as long as you only need pointers, void * is a multi-purpose pointer:

struct Group
{
    enum type{ pattern, group } t;
    char name[20];
    int id;
    void *children[20];    // cast elements to `Group *` or `Pattern *` depending on t
};
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • 1
    The cast to `Group **`/`Pattern **` is formally undefined, though. – Quentin May 20 '19 at 11:58
  • @Quentin: Yes, the correct way is to cast individual arrays elements to respectively `Group *` or `Pattern *` I was too lazy to take care of details, because it is so C-ish that I only posted it for completeness of possible solutions. But you got it ;-). I have edited my post. – Serge Ballesta May 20 '19 at 12:30
  • C-ish is actually a positive for me, so thank you for the simple yet useful suggestion – Ruptr May 20 '19 at 20:53
  • Btw, if you want C-centered approach, you can read up on [Tagged Union](https://en.wikipedia.org/wiki/Tagged_union) technique (which std::variant basically implements). – Dan M. May 20 '19 at 21:21
  • @DanM. Thanks man. – Ruptr May 20 '19 at 21:28
0

If you want to have a variable that is either type A, or B (or C...), you can use std::variant type which was introduced in C++17, or its custom implementations if you compiler doesn't support it. This is how it can look. For simple cases you can also do it manually using unions, although library solution is preferred. If you want specifically union/struct-only solution, I suggest you to direct your question to the C and not C++.

However, it looks like you are trying to create some sort of tree-like structure. For such structures in C++ I've found that simple inheritance works the best.

Dan M.
  • 3,818
  • 1
  • 23
  • 41
  • 1
    does `std::variant` allow incomplete types? – 463035818_is_not_an_ai May 20 '19 at 11:26
  • 1
    I just checked, it doesn't :\ – hegel5000 May 20 '19 at 11:27
  • @formerlyknownas_463035818 it allows pointers to incomplete types, which was the question. – Dan M. May 20 '19 at 11:31
  • @formerlyknownas_463035818 it's badly worded. Provided example uses pointers and talks about struct referencing itself, not using literal C++ references. C++ references don't make sense for example provided since you can't create an array of them. See author's comment to his question: `I am asking if it is possible to have a variable within the struct be of either type itself or type pattern.` – Dan M. May 20 '19 at 11:37
  • ah, sorry, got it ;). I didnt read OPs code too carefully before. Still my comment holds: Your question misses to mention that you cannot have a `std::variant` of incomlete types, but you have to use pointers (and then I am still confused what would be the point of using a `std::variant` in the first place, but thats probably just my confusion) – 463035818_is_not_an_ai May 20 '19 at 11:38
  • I wouldn't answer a questions tagged C++11 by a solution that requires C++17. (Or, at first, you can ask OP in comments about C++17 availability). – Daniel Langr May 20 '19 at 11:44
  • @DanielLangr as I wrote in the answer, there are C++11 implementations available in boost and other libs. – Dan M. May 20 '19 at 11:48
  • @formerlyknownas_463035818 Well in answers the direct question "if it is possible to have a variable within the struct be of either type itself or type pattern". Although It does seem like the question's author is trying to implement a tree-like structure for which something like a simple inheritance would be a way cleaner solution. – Dan M. May 20 '19 at 11:49
  • @DanM. Is inheritance ever really clean :) – Ruptr May 20 '19 at 20:49
  • Although i did tag as C++11 I am grateful for the std::variant suggestions. Thanks – Ruptr May 20 '19 at 20:50