3

In a C++ program, I have a struct that contains a pointer to another instance of its own type:

struct Foo
{
  const Foo* ptr;
};

I want to declare and initialize two const instances of this struct that point to each other:

const Foo f1 = {&f2};
const Foo f2 = {&f1};

However, this results in the compile-time error error: 'f2' was not declared in this scope (obviously because f2 is declared after f1, even though f1's declaration references it).

Is what I'm trying to do possible and reasonable? If it is, how do I make it work?

One workaround might be to avoid making f1 const, then reassign the pointer after f2 has been declared (f1.ptr = &f2;), but I'd rather avoid this if I can.

kwc
  • 307
  • 2
  • 8

2 Answers2

6

At namespace scope you can do e.g.

namespace my_constants {
    extern Foo const f1;
    extern Foo const f2;

    Foo const f1 { &f2 };
    Foo const f2 { &f1 };
}  // namespace my_constants

I can's see any really good solution for local scope, but you can in principle do

auto hack = []( Foo const* pfoo ) -> Foo const&
{
    static Foo const other = {pfoo};
    return other;
};

static Foo const    f1{ &hack( &f1 ) };
Foo const&          f2 = hack( 0 );
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • don't even need the `extern Foo const f1;` ! – M.M Apr 03 '14 at 02:44
  • Actually, it looks like I don't even need the namespace, do I? – kwc Apr 03 '14 at 02:52
  • Sorry, I should clarify that my struct definition and instance declarations are in the global scope, so it seems to work if I just add `extern Foo const f2;` before declaring f1. – kwc Apr 03 '14 at 03:09
  • +1 for that aweful hack. As an aside, it makes `f2` effectively `static`! You could really solve this with some `optional` trickery, so long as you can access the ptr-to before construction. – Yakk - Adam Nevraumont Apr 03 '14 at 04:36
3

You can put them both inside another struct.

struct Foo
{
  const Foo* ptr;
};

struct interlinked_foos {
  Foo a = { & b }; // An initializer may forward-reference a class member.
  Foo b = { & a };
} twofoos;

const Foo & f1 = twofoos.a;
const Foo & f2 = twofoos.b;

This is C++11. In C++03, it seems you would need to add a constructor to Foo but the principle still works.

Not only doesn't it require an object to be extern, this potentially encapsulates the pattern for reuse.

Edit: Here's a terser, but slightly less elegant version (it assumes the objects are the same type):

const Foo twofoos[] = { & twofoos[1], & twofoos[0] },
          & f1 = twofoos[0], & f2 = twofoos[1];
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421