How to hide a datum from everyone but class T - c++

I want a type A that will yield its hidden datum to an object of type T but hide the datum from everyone else. My C++ compiler happens to be GCC 4.4, but that shouldn't matter. Why won't this work?
#include <iostream>
template <class T> class A {
private:
int n1;
public:
friend class T;
A(const int n0 = 0) : n1(n0) {}
};
class B {
public:
int f(const A<B> a) const { return a.n1; }
B() {}
};
int main() {
const A<B> a(5);
const B b;
const int m = b.f(a);
std::cout << m << "\n";
return 0;
}
Incidentally, this works fine, except that it fails to hide the datum:
#include <iostream>
template <class T> class A {
private:
int n1;
public:
int n() const { return n1; }
A(const int n0 = 0) : n1(n0) {}
};
class B {
public:
int f(const A<B> a) const { return a.n(); }
B() {}
};
int main() {
const A<B> a(5);
const B b;
const int m = b.f(a);
std::cout << m << "\n";
return 0;
}
Does C++ really not allow a friend class to be specified at compile time as a template parameter? Why not? If not, then what alternate technique should I use to hide the datum? (One would prefer a compile-time technique if possible.)
What is my misunderstanding here, please?
(I see some answers to related questions here and here, but either they don't answer my particular question or I fail to understand that they do so. At any rate, maybe I am using the wrong technique altogether. Though I remain interested in why the friend class T fails, what I really want to know is how to hide the datum, whether with a friend or by other means.)
Thanks.

Your compiler is simply too old. C++11 allows you to declare template parameters as friends.
§11.3 [class.friend] p3
A friend declaration that does not declare a function shall have one of the following forms:
friend elaborated-type-specifier ;
friend simple-type-specifier ;
friend typename-specifier ;
If the type specifier in a friend declaration designates a (possibly cv-qualified) class type, that class is declared as a friend; otherwise, the friend declaration is ignored.
And it even contains an example of a template parameter as a friend:
class C;
// [...]
template <typename T> class R {
friend T;
};
R<C> rc; // class C is a friend of R<C>
R<int> ri; // OK: "friend int;" is ignored
C++03 sadly has no way to do this, however you can simply friend a single free function and let that act as "glue" code that takes the data from one class and passes it to the other. Another way might be the passkey pattern.

I don't know the standardese behind your error (refer to Xeo's answer), but I did find a workaround for C++03.
Instead of making T a friend, make one of T's member functions a friend:
#include <iostream>
template <class T> class A {
private:
int n1;
public:
friend int T::getN1(const A& a) const;
A(const int n0 = 0) : n1(n0) {}
};
class B {
public:
int f(const A<B> a) const { return getN1(a); }
B() {}
private:
int getN1(const A<B>& a) const {return a.n1;}
};
class C {
public:
int f(const A<B> a) const { return getN1(a); }
C() {}
private:
// Error, n1 is a private member of A<B>
int getN1(const A<B>& a) const {return a.n1;}
};
int main() {
const A<B> a(5);
const B b;
const int m = b.f(a);
std::cout << m << "\n";
return 0;
}
Alternatively, you can make a nested class/struct of T be a friend of A. This may be more convenient if there are several private members of A that you want T to have access to.
#include <iostream>
template <class T> class A {
private:
int n1;
public:
friend class T::AccessToA;
A(const int n0 = 0) : n1(n0) {}
};
class B {
public:
int f(const A<B> a) const { return AccessToA::getN1(a); }
B() {};
private:
friend class A<B>;
struct AccessToA
{
static int getN1(const A<B>& a) {return a.n1;}
};
};
class C {
public:
int f(const A<B> a) const { return AccessToA::getN1(a); }
C() {};
private:
friend class A<C>;
struct AccessToA
{
// Error, n1 is a private member of A<B>
static int getN1(const A<B>& a) {return a.n1;}
};
};
int main() {
const A<B> a(5);
const B b;
const int m = b.f(a);
std::cout << m << "\n";
return 0;
}

Related

Is there another simple way to do with c++ properties?

I've tried to use c++ properties and now I'm stuck with this:
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<class s, typename t>
class getonly {
protected:
friend s;
t value;
t set(); // operator =...
public:
t get(); // t operator...
};
};
class b : public a {
public:
getonly<b, int> id;
};
What I want is something like this, where getonly is parametrized by only the typename (int), and not the class (b):
class b : public a {
public:
getonly<int> id;
};
Is this possible? Can anyone help me?
It appears that you want a data member that can be read by any code, but that can only be changed by the containing class.
The attempt at providing friend-ship via template would not have compiled prior to C++11. It means that this code can not be easily modified to work with a C++03 compiler (with C++03 one could express the access restriction on modification via e.g. an owner credential argument to a setter). However, that concern becomes less significant every day.
Here's your code modified to compile, and with the inheritance changed from public to private (it doesn't make much sense to say that b "is-an" a):
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<class s, typename t>
class getonly {
protected:
friend s;
t value_;
public:
auto get() const -> t const& { return value_; }
operator t const& () const { return value_; }
getonly( t v ): value_( v ) {}
};
};
class b : private a {
public:
getonly<b, int> id;
void set_id( int x ) { id.value_ = 2*x; }
b(): id( 42 ) {}
};
#include <iostream>
auto main() -> int
{
using namespace std;
b obj;
cout << obj.id << endl;
obj.set_id( 333 );
cout << obj.id << endl;
}
So first off, this can be done with CRTP
template<typename s>
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<typename t>
class getonly {
protected:
friend s;
t value;
t set(); // operator =...
public:
t get(); // t operator...
};
};
class b : public a<b> {
public:
getonly<int> id;
};
But since you mentioned inheritance, are you aware that friend declarations are not inherited? If that is your goal, then there is a more elegant solution - do not use the property as a base class but as traits:
template<typename T, typename F>
class property_impl
{
friend F;
private:
T value_;
protected:
void set(T value)
{
value_ = value;
}
public:
T get()
{
return value_;
}
};
template<typename F>
class property_traits
{
template<typename T> using property = property_impl < T, F > ;
};
class foo : public property_traits < foo >
{
public:
property<int> id_;
};
class bar : public foo, public property_traits < bar >
{
public:
property<int> another_id_;
void doStuff(foo f)
{
auto value = f.id_.get();
// f.id_.set(5); <-- fails since friend is not inherited
}
};
int main(int argc, char** argv)
{
foo f;
auto value = f.id_.get();
bar b;
auto another_value = b.another_id_.get();
b.doStuff(f);
return 0;
}
This will give you the ability to inherit and specialize on each class that needs a property while retianing the fact, that only the class type used in specialization is able to modify the value.
Again, maybe you want that, I am not sure.

c++ class constant of its own class

Basically, I would like to declare constants of a class within the class itself:
class MyClass {
int itsValue;
public:
MyClass( int anInt) : itsValue( anInt) {}
static const MyClass CLASSCONST;
};
So I can access it like this;
MyClass myVar = MyClass::CLASSCONST;
But I can't find a way to initialize MyClass::CLASSCONST. It should be initilized inside the MyClass declaration, but at that point the constructor is not known. Any one knowing the trick or is it impossible in c++.
class MyClass {
int itsValue;
public:
MyClass( int anInt) : itsValue( anInt) {}
static const MyClass CLASSCONST;
};
const MyClass MyClass::CLASSCONST(42);
Here is a working example with definition outside the class.
The class declaration has a const static member which is initialized outside the class as it is a static member and of type non-integral. So initialization inside the class itself is not possible.
#include <iostream>
class test
{
int member ;
public:
test(int m) : member{m} {}
const static test ob ;
friend std::ostream& operator<<(std::ostream& o, const test& t)
{
o << t.member ;
return o;
}
};
const test test::ob{2};
int main()
{
std::cout << test::ob ;
}

How do I avoid forward declarations?

Let's say I have two classes, A and B:
class B;
class A
{
private:
int an_int;
B *something_else;
public:
A(int n) : an_int(n), something_else(nullptr) {}
};
class B
{
private:
int an_int;
A *something_else;
public:
B(int n) : an_int(n), something_else(nullptr) {}
};
How can I make it so that I don't have to prototype B in order to have a pointer to a B object in class A?
This solution is most probably what is intended in an exercise about inheritance where you can't use a forward declaration.
Instead of the forward declaration
class B;
you can define an interface like
struct I_whoop
{
virtual void whoop_whoop() = 0;
};
then let class B implement that interface, and just use a pointer to the interface.
Actually You can not if using concrete class.
But You can achieve your goal by using template parameters. Making class B a template parameter of template class A.
How can I make it so that I don't have to prototype B in order to have a pointer to a B object in class A?
Like this:
class A
{
private:
int an_int;
class B *something_else;
public:
A(int n) : an_int(n), something_else(nullptr) {}
};
class B
{
private:
int an_int;
class A *something_else;
public:
B(int n) : an_int(n), something_else(nullptr) {}
};
In C and C++ it has never been necessary for a type T to be
forward declared before the declaration of objects of type T *
(or const variants), because the declaration of a T * per se requires
the compiler only to know the size of a T *, not the size or definition
of a T, and the size of a T * is the same, regardless of T.
Here is a more fleshed-out illustration:
class A
{
private:
int an_int;
class B *something_else;
public:
A(int n, class B * pb = nullptr) : an_int(n), something_else(pb) {}
int get_int() const {
return an_int;
}
void set_B(class B * pb) {
something_else = pb;
}
class B * get_B() const {
return something_else;
}
};
class B
{
private:
int an_int;
class A *something_else;
public:
B(int n, class A * pa = nullptr) : an_int(n), something_else(pa) {}
int get_int() const {
return an_int;
}
void set_A(class A * pa) {
something_else = pa;
}
class A * get_A() const {
return something_else;
}
};
#include <iostream>
int main()
{
A a(1);
B b(2);
a.set_B(&b);
b.set_A(&a);
std::cout << a.get_B()->get_int() << std::endl;
std::cout << b.get_A()->get_int() << std::endl;
return 0;
}
Output:
2
1
(gcc 4.9.2/clang 3.5.2 -std=c++11 -Wall -pedantic)

How to use template parameter to choose method call?

I have a method which is templated and I want it to call a different method depending on the template. The reason I have this is so that the caller does not need to create an Object of type B just to get the correct implementation called, instead they should be able to just choose by the implementation by templating.
The problem is i'm receiving reference type to a const as the template T and I do not know how to use this to choose the correct overloaded method. Ideally this would also work if T were not a reference type. Any idea?
Note: I can't use template specialization because I need the impl virtual.
#include <iostream>
using namespace std;
class A {};
class B {};
class C {
public:
template <typename T>
void f() {
// T = const B&
impl(T()); // error: value-initialization of reference type ‘const B&’
}
protected:
virtual void impl(const A& a) {
cout << "A";
}
virtual void impl(const B& b) {
cout << "B";
}
};
int main() {
C c;
const B &b2 = B();
c.f<decltype(b2)>(); // T = const B&
return 0;
}
If you want to get a type [more] likely to be constructible, you should remove any references, e.g., using std::remove_reference<T> and all qualifiers, e.g., using std::remove_cv<T>. ... or, just std::decay<T> the type which also transforms arrays into pointers:
template <typename T>
void f() {
impl(typename std::decay<T>::type());
}
You can still use template specialization through a helper private template dispatcher to call correct version of impl - which can still be virtual. Like this, compiles and runs
#include <iostream>
using namespace std;
class A {};
class B {};
class C {
public:
template <typename T>
void f() {
// T = const B&
impl_dispatch<T>(); // error: value-initialization of reference type ‘const B&’
}
protected:
virtual void impl(const A& a) {
cout << "A";
}
virtual void impl(const B& b) {
cout << "B";
}
private:
template <typename T>
void impl_dispatch();
};
template <> void C::impl_dispatch<A const &>()
{
impl(B());
}
template <> void C::impl_dispatch<B const &>()
{
impl(A());
}
int main() {
C c;
const B &b2 = B();
c.f<decltype(b2)>(); // T = const B&
return 0;
}

C++ Compiler error in inherited template class

I'm getting a C++ compiler error that I don't understand and haven't been able to find
a fix or an explanation for. Here is a code snippet demonstrating the problem.
#include <iostream>
template<class T>
class A {
public:
A(int n) {data = new T[n]; }
const T &operator()(int i) const {return data[i];}
protected:
T *data;
};
template<class T>
class B : public A<T> {
public:
B(int n) : A<T>(n) {}
T &operator()(int i) {return this->data[i]; }
//const T &operator()(int i) const {return this->data[i];} // fixes problem
};
template<class T, int N>
class C : public B<T> {
public:
C() : B<T>(N) {}
private:
};
template<class T>
void doOp(const T &v) {
std::cout << v(0) << std::endl;
}
void templateTest()
{
C<double, 3> c;
c(0) = 5;
std::cout << c(0) << std::endl;
doOp(c);
}
If I un-comment the line in class B, the code compiles and executes correctly but I
don't understand why defining this operator function in class B is any different from
the definition in class A.
Thanks for the help.
Bill
The problem is that doOp() is invoking a non-const member function through a reference to const.
If you uncomment the commented line, a viable const member function will be found, and overload resolution will pick that version of the call operator.
Without uncommenting that line, the inherited version of the call operator is not found because it is being hidden by the overloaded call operator in the subclass.
To illustrate the problem of name hiding with a simpler example, consider the following program:
struct X
{
void foo() { }
};
struct Y : X
{
void foo(int) { }
};
int main()
{
Y y;
y.foo(42); // OK
y.foo(); // ERROR! Name hiding...
}
The compiler here won't be able to resolve the call to y.foo(), because X::foo() is being hidden by Y::foo() here.
To fix the problem, you could add a using declaration in Y:
struct X
{
void foo() { }
};
struct Y : X
{
using X::foo;
// ^^^^^^^^^^^^^
void foo(int) { }
};
int main()
{
Y y;
y.foo(42); // OK
y.foo(); // OK
}
Now both function calls are correctly resolved. In your program, you could add a similar using declaration for operator () of the base class:
template<class T>
class B : public A<T> {
public:
B(int n) : A<T>(n) {}
T &operator()(int i) {return this->data[i]; }
using A<T>::operator();
// ^^^^^^^^^^^^^^^^^^^^^^^
};