How to Make Std::Make_Unique a Friend of My Class

How to make std::make_unique a friend of my class

make_unique perfect forwards the arguments you pass to it; in your example you're passing an lvalue (x) to the function, so it'll deduce the argument type as int&. Your friend function declaration needs to be

friend std::unique_ptr<A> std::make_unique<A>(T&);

Similarly, if you were to move(x) within CreateA, the friend declaration would need to be

friend std::unique_ptr<A> std::make_unique<A>(T&&);

This will get the code to compile, but is in no way a guarantee that it'll compile on another implementation because for all you know, make_unique forwards its arguments to another internal helper function that actually instantiates your class, in which case the helper would need to be a friend.

Friend function is unable to construct a unique pointer of the class

In your case the function make_unique is trying to create an instance of Spam and that function is not a friend. Calling a non-friend function from inside a friend function does not imbue the non-friend function with friend status.

To solve this you can write in Foo:

std::unique_ptr<Spam> spam(new Spam(10));

Can't access private constructor from a friend class

The problem is that make_unique which is supposed to construct an instance of B is not a friend of B. Therefore it does not have access to B's private constructor.

You can use the following to achieve something similar:

std::unique_ptr<B> pB2 = std::unique_ptr<B>(new B("dummy3"));

In general it is advised to prefer make_unique to calling new yourself, and I do not encourage it in any way (see here: Differences between std::make_unique and std::unique_ptr with new).

But if you are bound to this specific class hirarchy it will solve your issue.

make_unique cannot access private constructor in static member

As proposed by yksisarvinen in the comments, a way to solve this is to just replace make_unique<T> by std::unique_ptr<T>(new T(S)).

class S {
public:
S() {}
};
class T {
private:
std::unique_ptr<S> a;
T(S);

public:
static std::unique_ptr<T> make_item() {
// Create S
std::unique_ptr<S> s_instance = std::make_unique<S>();
return std::unique_ptr<T>(new T(s_instance));
}
};

Error on MSVC when trying to declare std::make_unique as friend of my templated class

Trying to friend std functions puts you in dangerous territory because you're making assumptions about their implementations that aren't guaranteed by the standard. For example, you want std::make_unique to be a friend so that it can access your protected constructor, but what if std::make_unique's implementation delegates this to some other secret function? What you'd need then is to befriend that secret function, but it's secret, so you can't.

Other complications: Some forms of std::make_unique aren't exactly specified by the standard (though I don't think that applies to this exact example). Old versions of VC++ used macro magic to simulate variadic templates before the compiler had full support for variadic templates, so while there is a std::make_unqiue, it might not have the actual signature you expect.

make_unique doesn't compile for creating a singleton instance

The purpose of std::unique_ptr<> is to control the lifetime of the object pointed to. You may pass a std::unique_ptr<> around, but that will also transfer ownership of the object pointed to. This concept does not match very well with the concept of a singleton. There is only one place that is ever allowed to create (or delete) the singleton. You don't really need a std::unique_ptr<>for that. As already said in the comments, there are simpler ways for that. I would prefer @Praetorian's suggestion:

static A& getInstance() 
{
static A instance;
return instance;
}

The reason why you can't use std::make_unique<>() to instantiate your class is that the constructor is private. To access it, you need the accessing function to be a friend. Have a look at How to make std::make_unique a friend of my class for that. Another solution is to provide a public constructor requiring a private type as argument, as described int this solution.

How to access private Constructor from within inner class? C++14

This doesn't work because the real builder is std::make_unique, and it is neither a friend nor a member. Making it a friend is not really possible, because you don't know what internal function it delegates to, and it would defeat the purpose of a private constructor anyway.

You can just use bare new instead of std::make_unique, it will work in a pinch. If instead of a unique pointer you want a shared pointer, this becomes a bit more problematic, since the performance will not be as good.

Here's how to make it work for unique_ptr, shared_ptr or any other kind of handle.

#include <memory>

class Outer
{
private:
Outer();
public:
class Builder
{
private:
class InnerOuter;
public:
std::unique_ptr<Outer> build();
};
};

class Outer::Builder::InnerOuter : public Outer
{
public:
using Outer::Outer;
};

std::unique_ptr<Outer> Outer::Builder::build()
{
return std::make_unique<InnerOuter>();
}

Now only Outer::Builder can refer to (and construct) an InnerOuter, because it is a private class. But its constructor is public, so std::make_unique can access it.

Note, InnerOuter can access a private constructor of Outer because it is a member of a member of Outer and have member access to Outer.

how do I forward the templates arguments onto the std::make_unique when creating policy based class?

Figured this out.
It's turns out the syntax:

auto bar = std::make_unique<Bar<Policy2, Policy3>>();

works after all (on C++20, using MSVC v16.10.2).

It requires the following declaration to work:

std::unique_ptr<Bar<T,V>> _bar;

in addition I had to provide on CPP this as well (to avoid linker error):

template class Bar<concrete_policy1, concrete_policy2>;


Related Topics



Leave a reply



Submit