How can I access a protected constructor from a friend function? - c++

I created a class and I want to force anyone who's trying to construct an object, to use unique_ptr. To do that I thought of declaring the constructor protected and use a friend function that returns a unique_ptr. So here's 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 did some reading on friend functions and I understood that a friend function provides access to private/protected members of an object of a class.
Is there anyway I can make my example work?
Even without friend functions, my goal is to make the CreateA the only way for someone to create an object.
EDIT
I change the code a bit. I didn't mention that my class takes one template parameter. That makes things more complex apparently.

You can do it this way :-
#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;
}
Output :-
5
If you don't want to use friend function you can make the function static & call it like this :-
unique_ptr<A> u = A::CreateA(x);
EDIT :-
In reply to your edit I rewrote the program & it goes 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 & easy !!! But remember you cannot instantiate the object of A. Good Luck !!!

The 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 approach didn't work and how to use the friend approach correctly.
There are two problems in your original code. One is that make_unique is not actually a friend of A, so the call make_unique<A<T>>(myarg); does not have access to A's protected constructor. To avoid this , you can use unique_ptr<A<T>>(new A(myarg)) instead. Theoretically it would be possible to declare make_unique a friend but I'm not even sure of the right syntax for that.
The other issue is the template friends problem. Inside a class template, friend <function-declaration> actually declares a non-template friend.
The C++ FAQ suggests two possible workarounds. One of them is to define the friend function inline. However, in that case the function can only be found by argument-dependent lookup. But since the function does not take A<T> (or A<T> &) as argument, it can never be found this way. So this option is not viable to your situation -- it's more suited to operator overloading.
So the only fix is to declare (and optionally define) the template function before the class definition:
#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: It is possible to declare CreateA where I have defined it, and put the function definition later. However, the code I have posted works -- despite A not being defined when new A<T>(myarg) appears in the source -- because CreateA is not instantiated until it is called, at which point A will be defined.

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;
}

Related

Declare non-template function in a template class?

NOTE: this post is different from this one: Declare non-template friend function for template class outside the class, so please read my question before marking it as duplicate.
I want to declare a non-template friend function inside a class template, and the arguments and return type of that friend function is unrelated to the template argument. How should I do that?
Please note it is different from that previous question because in that question, arguments and return type of that friend function is related to the template argument.
Example, adapted from that question above:
// class.h
#include <iostream>
using namespace std;
template <typename T>
struct B
{
T value;
int value2;
B() : value2(1) {}
friend void modify(const int&); // unrelated to T!
void printValue2() {
modify(value2);
cout << value2 << endl;
}
};
// define friend function foo() in a class.cpp file, not in the header
void modify(const int &v) { v = v * 2 + 1; } // HOW should I write it?
// main.cpp
int main() {
B<int> b;
b.printValue2();
return 0;
}
I know I can declare modify() outside this template class so it becomes a vanilla, ordinary function. But I want only this template class to have access to modify(). Alternatively, to achieve this goal of access control, I could define modify() to be a static method in this template class, but that would make the method a template method, forcing me to define it in the header.
Followup: if the friend approach above doesn't work, how should I achieve the two goals at the same time:
access control: only that class template can access modify()
be able to define modify() in a *.cpp file, rather in a header.
Accepted Answer:
To achieve the two goals above, don't abuse friendship.
The best practice is let the class template privately inherit a non-template base class, and in that base class declare common non-template methods that are unrelated to template arguments.
Therefore, you are able to define these methods in a separate *.cpp file, reducing the header's size.
You might use private inheritance instead of friendship:
// class.h
#include <iostream>
class B_helper
{
protected:
static void modify(int &v);
};
template <typename T>
struct B : private B_helper
{
T value;
int value2;
B() : value2(1) {}
void printValue2() {
modify(value2);
std::cout << value2 << std::endl;
}
};
// class.cpp
void B_helper::modify(int &v) { v = v * 2 + 1; }
You do it like this:
// class.cpp
void modify(const int &v) { v = v * 2 + 1; }
You are effectively abusing friendship, but ok. What this means is that you need to work around what it means to declare a function with friend: It is only visible through ADL! Now there is no way to refer to modify, because modify doesn't depend on B, so B's scope is never searched for a function named modify.
There is a work-around, but it's not pretty. You need to declare modify in every function where you use it. You could also declare it in global scope, but then everyone can call it. Alternatively, you can always declare it in a detail namespace (but this has the same issue a bit):
template<typename T>
void B<T>::printValue2() {
void modify(const int&);
modify(value2);
cout << value2 << endl;
}
As I said in the comments, friendship controls access to a class. As long as your function modify() is a standalone function, it cannot be befriended. As you want to call it from a template, it cannot be hidden it in a .cpp file either, but must be visible with the definition of the class template B and its member using modify().
One solution is to put modify as a static method in a auxiliary non-template class, which in turn befriends the template B<>.
// file foo.h (header)
namespace foo {
template<typename> class B; // forward declaration
class exclusive_for_B
{
template<typename T>
friend class B<T>;
static void modify(int&x) // must take int&, not const int&
{ x &= x+42; }
};
template<typename T>
class B
{
int val;
public:
...
void printvalue()
{
exclusive_for_B::modify(val); // access via friendship
std::cout << val << '\n';
}
};
}

A trouble in definition a friend function of template class in the namespace in c++

namespace N
{
template<typename tname> class C
{
public:
friend void f(int, C<tname>);
};
}
template<typename tname>
void N::f(int, N::C<tname>)
{
}
I am creating a friend function f like above but the compiler informed me this error :
'f': is not a member of N.
Meanwhile, without the namespace, my code will run correcly.
My code will be correct too when I use normal class instead of generic class (no remove namespace).
And it will also have no error with fully declaration. Like following code:
namespace N
{
template<typename tname> class C
{
public:
friend void f(int, C<tname>)
{
//mycode
}
};
}
Could someone help me fix this error in my first code? Thank you very much.
The friend declaration does not mean that the function is now a member of that class. It only means that f has access to the private members of C.
So if f is in the global namespace it cannot be referenced as being inside namespace N with N::f, it is still only a ::f, even after the friend declaration.
In the second example you're declaring f as a member function and declaring it a friend which I'm not sure serves a purpose.
The following compiles:
namespace N
{
template<typename tname>
class C;
template<typename tname>
void f(int, C<tname>);
template<typename tname> class C
{
public:
friend void f(int, C<tname>);
};
}
template<typename tname>
void N::f(int, N::C<tname>)
{
}
int main()
{
}

Access specifiers and rvalue references

I have the following piece of code, which doesn't compile (the compiler complains that B::fn is inaccessible).
#include <iostream>
using namespace std;
template<typename T>
class B
{
public:
void fn(T &&obj)
{
cout<<"base version\n";
}
};
template<typename T>
class A : public B<T>
{
private:
using B<T>::fn;
public:
void fn(const T &obj)
{
cout<<"derived version\n";
}
};
int main()
{
A<int *> a;
a.fn(new int(5));
}
To make the code work, it seems that I can
define a separate void fn(T &&obj), in the derived class, or,
make the inheritance private and do away with the access specifier
Could anyone please explain why my current code doesn't work, but the above approaches do?
[UPDATE]: I undersand that B::fn would be private. The reason I'm confused is that class A : private B<T> fixes the problem.
with:
private:
using B<T>::fn;
B<T>::fn is visible, but private.
replace by public and it would also be public.
If you remove the using B<T>::fn;, the B<T>::fn is hidden by A::fn,
so the call in main calls A::fn.

very non-trivial template friend declaration

class Foo
{
template <typename T> friend void T::persist(void);
int test;
};
class Bar
{
Foo foo;
void persist(void) { foo.test = 42; } // fails
}
With this, I hope that persist() member method of every class which defines it will be a friend of foo. The strange friend line compiles, but seems to do nothing.
Thank you in advance.
You cannot do that. You cannot befriend a member of all types, and your template-friend declaration is ill-formed. There is no template in:
class Foo
{
template <typename T>
friend void T::persist(void);
int test;
};
Note that the friend declaration is not a template. You can befriend a template function or class, but there is neither of them in the code above.
A simple workaround would be to create a helper class from which you derive and provides the accessor:
class Foo {
friend class FooAccessor;
int value;
};
class FooAccessor {
protected:
void write( Foo& f, int value ) {
f.value = value;
}
};
class FooUser : private FooAccessor {
Foo f;
void persist() {
write( f, 42 );
}
};
But you might want to revisit the design and look for alternatives, note that making fields private and then allowing every other class to access them through a friend declaration is not much better than just having the fields public. If you care to explain what you are trying to achieve, someone might be able to help you.

Two-phase lookup: can I avoid "code bloat"?

Two-phase lookup question:
Is there a more synthetic way to write this code, i.e. avoiding all those using directives?
Something like using CBase<T>; is what I would like, but it is not accepted.
#include <iostream>
template <typename T>
class CBase
{
protected:
int a, b, c, d; // many more...
public:
CBase() {
a = 123; c = 0;
}
};
template <typename T>
class CDer : public CBase<T>
{
// using CBase<T>; // error, but this is what I would like
using CBase<T>::a;
using CBase<T>::b;
//...
public:
CDer() {
std::cout << a << this->c;
}
};
int main()
{
CDer<int> cd;
}
In my real code there are many more member variables/functions, and I was wondering if it is possible to write shorter code in some way.
Of course, using the this->c syntax does not solve the problem...
Thank's!
gcc 4.1
MacOS X 10.6
I reduced the testcase and then consider three options
template<typename T> struct Base { int a; };
Option 1
template<typename T> struct Der : Base<T> {
void f() {
int &ra = Der::a;
// now use ra
}
}
Option 2
template<typename T> struct Der : Base<T> {
void f() {
// use this->a instead
// or Der::a
}
}
Option 3
// use your using declarations
It doesn't look like most of those variables are parameterized. Does CBase use them all, or just a? If not, move them into a new non-template base of CDer.
Or, pack them all into a POD struct and then using CBase<T>::m_ints;.
High overhead solution: non-templated virtual base.
Not sure but worth a try: nest the definition of CDer inside CBase and then typedef it into namespace scope.