6

Is it possible to have a struct containing references to structs. And how are these initialized? See short example below.

Thanks

typedef struct {
  int a;
}typeInner1;


typedef struct {
  int b;
}typeInner2;


typedef struct {
  typeInner1 &one;
  typeInner2 &two;
}typeOuter;

void fun2(typeOuter *p){
  p->one.a =2;
  p->two.b =3;
}


void fun(typeInner1 &arg1,typeInner2 &arg2){
  typeOuter *ptr = new typeOuter;//<-- how to write initializer
  fun2(ptr);
}


int main(){
  typeInner1 arg1;
  typeInner2 arg2;
  fun(arg1,arg2);

  //now arg1.a should be 2 and arg2.a=3
}

Ok thanks for all the input. I also had to modify the typedef of the typeOuter to make it work. Full working code below for other people finding this post.

#include <cstdio>
typedef struct {
  int a;
}typeInner1;


typedef struct {
  int b;
}typeInner2;


typedef struct typeOuter_t {
  typeInner1 &one;
  typeInner2 &two;
  typeOuter_t(typeInner1 &a1, typeInner2 &a2) : one(a1), two(a2) {}
}typeOuter;

void fun2(typeOuter *p){
  p->one.a =2;
  p->two.b =3;
}


void fun(typeInner1 &arg1,typeInner2 &arg2){
  typeOuter *ptr = new typeOuter(arg1,arg2);
  fun2(ptr);
}


int main(){
  typeInner1 arg1;
  typeInner2 arg2;
  fun(arg1,arg2);

  //now arg1.a shoule be 1 and arg2.a=3
  fprintf(stderr,"arg1=%d arg2=%d\n",arg1.a,arg2.b);
}
monkeyking
  • 6,670
  • 24
  • 61
  • 81
  • 1
    BTW, `typedef struct {...} foo;` is not "idiomatic" in C++, simply writing `struct foo {...};` is more usual (and does let you use `foo` as a type name directly). – Mat Feb 09 '13 at 14:33

6 Answers6

9

Give typeOuter an appropriate constructor:

struct typeOuter
{
  typeInner1 &one;
  typeInner2 &two;
  typeOuter(typeInner1 &a1, typeInner2 &a2) : one(a1), two(a2) {}
};



void fun(typeInner1 &arg1, typeInner2 &arg2) {
  typeOuter *ptr = new typeOuter(arg1, arg2);
  fun2(ptr);
}
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
5

Before C++11, you will need a constructor for your struct typeOuter, and initialize the member references in the initializer list:

typeOuter(typeInner1& i1, typeInner2& i2) : one(i1), two(i2) {}

With C++11 you also have the option of using an initializer list directly (without defining a constructor yourself):

typeOuter *ptr = new typeOuter { arg1, arg2 };
Mat
  • 202,337
  • 40
  • 393
  • 406
3

In C++ you can create a constructor for your struct. Structs are basically classes with public as default access modifier.

struct Example
{
    // struct fields..

    Example(); // initialize struct objects.
    ~Example(); // perform clean up if necessary.
};
3

Your problem is not with having references to structs, but with initializing references in general. References cannot be default-initialized, no matter whether they are references to a struct or to a built-in type.

int& x; // ERROR! Non-initialized reference to int
C& y; // ERROR! Non-initialized reference to a struct C
int z;
C w;
int& a = z; // OK: Initialized reference to int
C& b = w; // OK: Initialized reference to struct C

When your references are member variables of a struct, on the other hand (no matter what type they refer to), they must be bound as soon as your struct is constructed (just as regular references). Default-constructing your struct and then binding the references is not an option, because it is done in two steps, and references would be uninitialized after the first step.

Therefore, you have to provide a constructor for your struct and initialize your references there:

struct typeOuter {
  typeOuter(typeInner1& o, typeInner2& t) : one(o), two(t) { }
  typeInner1 &one;
  typeInner2 &two;
};    

Your fun() function would then look like this:

void fun(typeInner1 &arg1,typeInner2 &arg2){
    typeOuter *ptr = new typeOuter(arg1, arg2);
    fun2(ptr);
}
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
1

You could add a constructor, but you can also use aggregate initialization along with a factory function. This works in all versions of C++:

struct A
{
   int& i;
};

A make_a(int& i)
{
   A a = {i};
   return a;
}

int main()
{
   int i = 0;
   A* a = new A(make_a(i));
}
dalle
  • 18,057
  • 5
  • 57
  • 81
0

Uhm..

#include <cstdio>

struct typeInner1
{
    typeInner1(int a = 0) : m_a(a) {} // typeInner1 constructor
    int m_a;
};

struct typeInner2
{
    typeInner2(int b = 0) : m_b(b) {} // typeInner2 constructor
    int m_b;
};

struct typeOuter
{
    typeOuter(typeInner1& one, typeInner2& two) : m_one(one), m_two(two) {} // typeOuter constructor

    typeOuter& set(int a, int b) { m_one.m_a = a; m_two.m_b = b; return *this; }
    typeOuter& print() { printf("typeInner1 a is %i and typeInner2 b is %i\n", m_one.m_a, m_two.m_b); return *this; }

    typeInner1& m_one;
    typeInner2& m_two;
};

typeOuter fun(typeInner1& arg1, typeInner2& arg2)
{
    return typeOuter(arg1, arg2);
}

int main()
{
  typeInner1 arg1;
  typeInner2 arg2;

  fun(arg1, arg2).print().set(101, 202).print().set(202, 303).print();

  return 0;
}

Outputs

typeInner1 a is 0 and typeInner2 b is 0
typeInner1 a is 101 and typeInner2 b is 202
typeInner1 a is 202 and typeInner2 b is 303
Edward A
  • 2,291
  • 2
  • 18
  • 31