Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make boost::make_shared a friend of my class

I have written a class with protected constructor, so that new instances can only be produced with a static create() function which returns shared_ptr's to my class. To provide efficient allocation I'd like to use boost::make_shared inside the create function, however the compiler complains that my class constructor is protected inside boost::make_shared. I decided to my boost::make_shared a friend of my class but I'm puzzled about the syntax. I tried

template< class T, class A1, class A2 >
friend boost::shared_ptr<Connection> boost::make_shared(const ConnectionManagerPtr&, const std::string&);

but the compiler gived me syntax errors. Please help.

like image 474
kyku Avatar asked Jul 31 '10 14:07

kyku


2 Answers

You don't need to template the friend part, but you need to signify that the friend function is a template:

friend boost::shared_ptr<Connection> boost::make_shared<>(/* ... */);
//                                                     ^^

That works with Comeau and current GCC versions but fails with VC. Better would be the following form:

friend boost::shared_ptr<Connection> boost::make_shared<Connection>(/* ... */);

That works across multiple compilers now - i tested it on VC8, VC10, GCC 4.2, GCC 4.5 and Comeau 4.3.

Alternatively using a qualified name to refer to a particular instance of the function template as Martin does should work and does with Comeau, but GCC chokes on it.

A useful alternative that doesn't depend on the implementation details of make_shared() (and thus also works with VC10s TR1 implementation) is to use the pass-key-idiom for access-protection of the constructor and to befriend the create() function instead, e.g.:

class Connection {
// ...
public:
    class Key {
        friend boost::shared_ptr<Connection> create(const ConnectionManagerPtr&, 
                                                    const std::string&);
        Key() {}
    };
    Connection(const ConnectionManagerPtr&, const std::string&, const Key&);
};

boost::shared_ptr<Connection> create(const ConnectionManagerPtr& p, 
                                     const std::string& s) 
{
    return boost::make_shared<Connection>(p, s, Connection::Key());
}
like image 156
Georg Fritzsche Avatar answered Sep 18 '22 22:09

Georg Fritzsche


I would try without the template part. After all, you want a specific instantiation of the (template) function to be a friend of your class, aren't you? Does

friend boost::shared_ptr<Connection> boost::make_shared(const ConnectionManagerPtr&, const std::string&);

work?

If that's not the solution, it might be helpful to give us the compiler messages you're getting ...

like image 26
MartinStettner Avatar answered Sep 20 '22 22:09

MartinStettner