Re: small exercise :-)
On 2/17/07 1:20 AM, in article
1171670604.331076.235910@j27g2000cwj.googlegroups.com, "Michael Kilburn"
<crusader.mike@gmail.com> wrote:
Here is the small problem that looks quite hard to crack. Task is to
compile code below without using operator== that takes C by value.
Basically -- I've been trying to implement something similar to C#
accessors. Initial plan was to make them as 'undetectable' as possible
-- i.e. moving from exposed data member to accessors (and backwards)
should not require client code change (not taking '()' into account
however).
But it looks like that C++ rules does not allow to create such object.
For example, code below compiles if you use second A::data()
declaration.
template<class T>
class accessor
{
T& m_ref;
typedef accessor<T> Self;
template<class T> friend inline accessor<T> make_accessor(T& d)
{ return accessor<T>(d); }
accessor();
accessor(T& ref) : m_ref(ref) {}
public:
// compiler generated cctor & dtor are ok
template<class C> inline operator C() { return m_ref; }
// operator==
template<class C> friend inline bool operator==(Self l, C const&
r) { return l.m_ref == r; }
template<class C> friend inline bool operator==(C const& l, Self
r) { return l == r.m_ref; }
friend inline bool operator==(Self l, Self r) { return l.m_ref ==
r.m_ref; }
};
struct B
{
int k;
B(int a = 0) : k(a) {}
operator int() {return k;} // no const deliberately!
//friend inline bool operator==(B const& l, B const& r) { return
l.k == r.k; }
//bool operator==(B const& r) const { return k == r.k; }
};
class A
{
B m_data;
public:
A(int d) : m_data(d) {}
accessor<B> data() throw() { return make_accessor(m_data); }
//B& data() throw() { return m_data; }
};
main()
{
bool volatile bval;
A a1(1);
A a2(2);
B b;
bval = a1.data() == a2.data();
bval = A(3).data() == a2.data();
bval = a1.data() == A(3).data();
bval = b == a2.data();
bval = a1.data() == b;
bval = 5 == a2.data();
bval = a1.data() == 5;
bval = a1.data() == B();
bval = B() == a2.data();
int aa = a1.data();
}
Just have A::data() return a const reference to its B data member. Then
implement equality comparisons between two B objects and between a B object
and an int:
struct B
{
public:
B(int a = 0) : k(a) {}
bool operator==(const B& rhs) const
{
return k == rhs.k;
}
friend bool
operator==(int lhs, const B& rhs)
{
return lhs == rhs.k;
}
private:
int k;
};
class A
{
public:
A(int d) : m_data(d) {}
const B& data() const
{
return m_data;
}
private:
B m_data;
};
The above code is enough to compile all but the last line of main() (the one
that assigns A::data()'s return value to an int). Now this assignment raises
an important question: what type does A::data() return - is it an int or a B
object?
If B's and int's are distinct types, then the program should not suport
implicitly converting from one type to the other.
On the other hand, if B is some sort of a proxy class for ints, then further
simplification is in order. The following definitions of the A and B classes
are sufficient to support main() in its entirety:
struct B
{
public:
B(int a = 0) : k(a) {}
operator int() const
{
return k;
}
private:
int k;
};
class A
{
public:
A(int d) : m_data(d) {}
int data() const
{
return m_data;
}
private:
B m_data;
};
Greg
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]