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
Can MACros Be Overloaded by Number of Arguments
How to Copy Contents of a Directory into Build Directory After Make with Cmake
Detailed Guide on Using Gcov with Cmake/Cdash
What Is a Good Oo C++ Wrapper for SQLite
What Does the Fpermissive Flag Do
Cleaning Up an Stl List/Vector of Pointers
Netbeans 7.2 Shows "Unable to Resolve Identifier" , Although Build Is Successful
How to Create a Simple Qt Console Application in C++
Has Anyone Ever Had a Use for the _Counter_ Pre-Processor MACro
Constexpr Not Compiling in Vc2013
How to Release Pointer from Boost::Shared_Ptr
Is C++11's Long Long Really at Least 64 Bits
Why Doesn't Vector::Clear Remove Elements from a Vector