Victor Bazarov <v.********@comAcast.net> writes:
Niklas Norrthon wrote:
// foo.cc (third and final version */
#include "foo.h"
namespace {
template <typename Foo_ImpDet>
void helper(Foo_ImpDet& i)
{
/* do something */
i.f(); /* works for all types of i with a public f() member
*/ }
}
void friend_fun(Foo::ImplementationDetails& imp) /* unchanged from
first try */
{
helper(imp);
}
I'm not asking any questions, just wanted to share. Comments are
welcome.
I have one question which, when you answer it, can lead to more questions,
of course.
Who and how uses 'friend_fun' function? To call it one would need to
expose 'imp' member, and that's already implicitly allowing access to
private parts of Foo. I would be surprised if you could do the same
thing if 'friend_fun' would have 'Foo' as its argument. Or maybe not.
Try changing it to
void friend_fun(Foo&);
and see what needs to be changed in your template technique (if anything
at all). I am just curious.
You are right. I meant to have the friend_fun to take an argument of Foo&
and not Foo::ImplementationDetails&. I was typing too fast. The fourth
and (hopfully) final version of the above:
// foo.h
#ifndef H_FOO
#define H_FOO
class Foo
{
private:
struct ImplementationDetails {
int x;
int f() const;
} imp;
/* more data members */
public:
/* public interface */
Foo();
void mem_fun();
/* etc. */
/* friends */
friend void friend_fun(Foo&); };
#endif
// foo.cc (fourth and final version */
#include "foo.h"
namespace {
template <typename Foo_ImpDet>
void helper(Foo_ImpDet& i)
{
/* do something */
i.f(); /* works for all types of i with a public f() member */
}
}
void friend_fun(Foo& foo)
{
helper(foo.imp);
}
As I mentioned in my first post, a concrete example of when this technique
could be useful is a class for which operator<< is defined:
class Qwerty
{
public:
Qwerty();
virtual ~Qwerty() { }
/* etc */
friend std::ostream& operator<< (ostream&, const Qwerty&);
private:
typedef std::vector<std::string> Vec;
typedef Vec::const_iterator Iter;
Vec my_data;
};
template <typename Iter>
bool is_visible(Iter i)
{
/* complex logic to find out if *i should be printed or not */
return result_of_logic_above;
}
std::ostream& operator<< (ostream& os, const Qwerty& q)
{
for (Qwerty::Iter i = q.my_data.begin(); i != q.my_data.end(); ++i)
{
if (is_visible(i)) {
os << *i << ' ';
}
}
return os;
}
/Niklas Norrthon