4

The question is self explanatory, but here's an example if desired:

Say I have a class 'Thing' with a private constructor, that is friends with a function 'make_thing':

class Thing
{
    friend std::shared_ptr<Thing> make_thing();

    Thing()
    {
        std::cout << "Thing constructor" << std::endl;
    }
};

The 'make_thing' function has a struct defined inside it:

std::shared_ptr<Thing> make_thing()
{
    // err: Thing::Thing() is private within make_shared
    // auto thing = std::make_shared<Thing>();

    // this is okay
    struct AccessThing : public Thing {
        AccessThing() : Thing() { }
    };

    auto thing = std::make_shared<AccessThing>();
    return thing;
}

This compiles and works in gcc 4.8.2, clang 3.5 and msvc 2013. I can't call

make_shared<Thing>()

because Thing has a private constructor. However, I can get around this by creating a struct (AccessThing) with a public constructor that in turn calls Thing's private constructor, and then pass that to make_shared. To me this makes sense if AccessThing is a friend of Thing.

So what are the rules concerning how friendship is conferred to structs/classes defined within a friend function?

Prismatic
  • 3,338
  • 5
  • 36
  • 59
  • 2
    I have not been able to back this with a quote, but I have the impression that the function has access, and `AccessThing` is part of the code in the function... Other than that, if what you want is to control who can create your objects and want to use `make_shared` you can use a *constructor key*: make the constructor public, but have it take a type that is private. A friend function will be able to create an instance of that type and pass it to the constructor through `make_shared` – David Rodríguez - dribeas Feb 26 '15 at 04:33
  • 1
    Yes, I'd like to use a factory function and call make_shared from it. There were a few methods listed in this Q (I derived my attempt from this as well): http://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const, including something similar to the constructor key idiom you mentioned. However, after trying to throw a struct in a friend function and have it work, I was curious as to what the underlying rules were. Also, this is probably best suited for another question but are there any benefits in using the key method? – Prismatic Feb 26 '15 at 04:48

1 Answers1

3

This is the very first paragraph of the standard section on local classes:

A class can be declared within a function definition; such a class is called a local class. The name of a local class is local to its enclosing scope. The local class is in the scope of the enclosing scope, and has the same access to names outside the function as does the enclosing function.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Thanks! I wanted confirmation that the behavior was explicitly defined and your answer makes it pretty clear – Prismatic Feb 26 '15 at 16:58