11

The following appears to be a pattern employed by ZeroC ICE in the code it auto-generates, which appears to me to be a way they have made singletons (not sure why) for many releases of their tool now. Various compilers have no problem with it, until I found today that Visual Studio 2015 Update 1 (VS version 14.0.24720.00, VC++ version 19.00.23506) emits an error. Before Update 1, VS2015 also had no problem with it. I'm not sure whether it's a bug (regression?) in the VS2015 C++ compiler with Update 1, or bad (not standards-conformant) C++ code that other compilers let slide.

Here is an example of the code pattern:

class Foo {
protected:
    virtual ~Foo() {}

    friend class Foo_init;
};

class Foo_init {
public:
    Foo init;
};

static Foo_init staticFooInit;

VS2015 Update 1 emits these errors:

example.cpp(13): error C2248: 'Foo::~Foo': cannot access protected member declared in class 'Foo'
example.cpp(3): note: see declaration of 'Foo::~Foo'
example.cpp(1): note: see declaration of 'Foo'

I found one (as yet unanswered) ZeroC ICE forum post which seems related to this, but otherwise I haven't found out in my Google searching anything that convinces me whether this is a compiler issue or bad code. I admit I don't know ZeroC ICE very well, nor do I use C++ friend classes enough to have a deep understanding of what you can and can't do with them. I'm hoping someone more knowledgeable can shed some light on it.

Richard Walters
  • 1,464
  • 8
  • 16

2 Answers2

1

I am not 100% sure on your exact problem, but it reminds me of a problem I had a while ago, where forward declared classes would have an unexpected scope. this page cppreference class highlights the rules, that a forward-declared class has the most local scope. However, your example on my VS2015u3 does not fail either.

I think the fix is probably to forward declare the class which is a friend before the class, so that it has a well defined scope.

When you have a class such as

class Example {
     int someFunction( class SomeOtherClass & param );
};

The compiler treats declaration of SomeOtherClass which is within the local scope.

This means that

class Example {
     int someFunction( class SomeOtherClass & param );
};

class SomeOtherClass {
          ...
};

Declares three classes Example Example::SomeOtherClass and SomeOtherClass

Changing your example to

class Foo_init;

class Foo {
  protected:
    virtual ~Foo() {}

    friend Foo_init;
 };

class Foo_init {
  public:
    Foo init;
 };

 static Foo_init staticFooInit;

Should work

mksteve
  • 12,614
  • 3
  • 28
  • 50
-7

You have used an identifier that starts with an underscore and then a capital letter. These names are reserved for the implementation, and using them in user code is undefined behaviour.

Puppy
  • 144,682
  • 38
  • 256
  • 465