How can I access the protected constructor from a friend function?

I created a class, and I want to force anyone trying to build an object to use unique_ptr . To do this, I thought about declaring the constructor protected and used the friend function, which returns unique_ptr . So here is an example of what I want to do:

 template <typename T> class A { public: friend std::unique_ptr<A<T>> CreateA<T>(int myarg); protected: A(int myarg) {} }; template <typename T> std::unique_ptr<A<T>> CreateA(int myarg) { // Since I declared CreateA as a friend I thought I // would be able to do that return std::make_unique<A<T>>(myarg); } 

I read a little about friend functions, and I realized that friend function provides access to private / protected members of a class object.


Is there a way to make my example work?

Even without friend functions, my goal is to make CreateA way only to create an object.

EDIT

I am changing the code a bit. I did not mention that my class accepts one template parameter. This makes things more complicated, apparently.

+8
c ++ friend-function
source share
3 answers

You can do it as follows: -

 #include <iostream> #include <memory> using namespace std; class A { int arg; public: friend unique_ptr<A> CreateA(int myarg); void showarg() { cout<<arg; } protected: A(int myarg): arg(myarg) {} }; unique_ptr<A> CreateA (int myarg) { return std::unique_ptr<A>(new A(myarg)); } int main() { int x=5; unique_ptr<A> u = CreateA(x); u->showarg(); return 0; } 

Exit: -

 5 

If you do not want to use the friend function, you can make the function static and call it like this: -

 unique_ptr<A> u = A::CreateA(x); 

EDIT: -

In response to your editing, I rewrote the program, and it looks like this: -

 #include <iostream> #include <memory> using namespace std; template <typename T> class A { T arg; public: static std::unique_ptr<A> CreateA(T myarg) { return std::unique_ptr<A>( new A(myarg) ); } void showarg() { cout<<arg; } protected: A(T myarg): arg(myarg) {} }; int main() { int x=5; auto u = A<int>::CreateA(x); u->showarg(); return 0; } 

Simple and easy !!! But remember that you cannot create an instance of object of A Good luck !!!

+3
source share

Create a static function that instantiates the protected constructor.

  #include<iostream> #include<string.h> #include<ctype.h> #include<math.h> #include <memory> using namespace std; template< typename T > class A { public: static void CreateA(int myarg, std::unique_ptr<A<T>>& objA, T t) { std::unique_ptr<A<T>> objB(new A(myarg, t)); objA = std::move(objB); } protected: A(int myarg, T t) { m_t = t; } private: T m_t; }; int main() { int myArg = 0; std::unique_ptr<A<int>> anotherObjA; A<int>::CreateA(myArg, anotherObjA, myArg); return 0; } 
+2
source share

Other answers suggest using a static template function, which I agree is the best solution because it is simpler.

My answer explains why your friend wasn’t working and how to properly use the friends approach.


There are two problems in the source code. One of them is that make_unique is not really a friend of A , so calling make_unique<A<T>>(myarg); does not have access to A protected constructor. To avoid this, you can use unique_ptr<A<T>>(new A(myarg)) instead. Theoretically, one could declare a make_unique friend, but I'm not even sure of the correct syntax for this.

Another problem is the problem with friends in templates . Inside the class template, friend <function-declaration> actually declares a friend without templates.

C ++ FAQs offer two possible solutions. One of them is to define a friend function inline. However, in this case, the function can only be found using an argument-dependent search. But since the function does not accept A<T> (or A<T> & ) as an argument, it can never be found this way. Thus, this option is not suitable for your situation - it is more suitable for operator overload.

So the only fix is ​​to declare (and optionally define) the template function before defining the class:

 #include <memory> template<typename T> class A; template <typename T> std::unique_ptr<A<T>> CreateA(int myarg) { return std::unique_ptr<A<T>>{new A<T>(myarg)}; } template <typename T> class A { friend std::unique_ptr<A<T>> CreateA <> (int myarg); // refers to existing template ^^ protected: A(int myarg) {} }; int main() { auto x = CreateA<int>(5); } 

Note. You can declare CreateA , where I defined it, and put the function definition later. However, the code I posted works even though A not detected when new A<T>(myarg) appears in the source, because CreateA not created before it is called, after which A will be defined.

+2
source share

All Articles