1

If I have a class with a private construction, using boost::make_shared() to construct a shared_ptr of that class from within a member function of that class will issue a compiler error using gcc 4.6.

#include "boost/shared_ptr.hpp"
#include "boost/make_shared.hpp"

class Foo
{
private:
    Foo(int a){};
public:
    static boost::shared_ptr<Foo> do_foo(){ return boost::make_shared<Foo>(5); }
    friend template boost::shared_ptr<Foo> boost::make_shared<Foo>( Arg1 && arg1, Args && ... args );
}

int main()
{
    auto f = Foo::do_foo();
}

A call to Foo::do_foo will result in a compiler error.

Any thoughts?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Raindog
  • 1,468
  • 3
  • 14
  • 28

2 Answers2

3

Unfortunately, it is not specified which function actually calls the constructor in make_shared, so you cannot make that function a friend. If you have a class with a private constructor like this then you thus cannot construct an instance with make_shared.

However, what you can do is create a derived class with a public constructor that calls the appropriate base class constructor, and make that derived class a friend (so it can call the private constructor):

class Foo
{
private:  
    Foo(int a){};  
public:  
    static boost::shared_ptr do_foo();
    friend class DerivedFoo;
};

class DerivedFoo: public Foo
{
public:
    DerivedFoo(int a):
        Foo(a)
    {}
};

boost::shared_ptr<Foo> Foo::do_foo(){ return boost::make_shared<DerivedFoo>(5); }

If DerivedFoo is in an anonymous namespace in the .cpp file that defines do_foo then functions in other .cpp files will still not be able to construct any instances of Foo directly, and users will not be able to tell that what they have is actually a DerivedFoo.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155
0

You need, at the very least, to provide template arguments in a few places.

class Foo  
{  
private:  
    Foo(int a){};  
public:  
    static boost::shared_ptr<Foo> do_foo(){ return boost::make_shared<Foo>(5); }
    friend template boost::shared_ptr<Foo> boost::make_shared<Foo>( Arg1 && arg1, Args && ... args );
}  
kenm
  • 23,127
  • 2
  • 43
  • 62
  • @sellibitze Probably shouldn't be there, but I just copy-pasted the OP's code. `make_shared` does take variable number of arguments, and it passes them on to the target type's constructor. – kenm Sep 10 '10 at 14:09