P
Peteris Krumins
Hello!
I was playing around pimpl idiom and discovered that there is a problem
with it if a class member template function exists which has to access
private data, since only the forward declaration of pimpl class is
provided.
Example:
class Foo
{
private:
struct foo_impl;
foo_impl *pimpl;
public:
// ...
//
template <typename T>
T bar()
{
// bar() has to access private data which is located
// in pimpl.
// for example,
int id = pimpl->baz;
// ...
}
};
To allow the template be instantiated for any type is has to be
left in the interface of Foo class. But then it cannot access
pimpl->baz because pimpl has only been forward declared.
I have three solutions but I do not like any of them.
The first solution is to include or write the definition of
foo_impl class in the same file where Foo's interface is,
so Foo::foo_impl was defined.
I don't like because it would not reduce compile times and probably
will make client code to be recompiled since header file would have
changed since last compile and most tools for automatic compilation
look at modification times.
The second solution is to create a global function which takes
a reference to Foo and make this function a friend to Foo.
Example,
class Foo {
// ...
template <typename T>
friend int bar(Foo &foo);
// ...
};
and somewhere
template <typename T> int bar(Foo &foo) { return foo->impl->baz; }
As bar() is friend to Foo, it can access private pimpl.
I don't like this solution because i break interface of Foo, instead
of a convenient member function a global has to be added and an object
has to be passed to this function.
The third solution is the simplest, bring the particular private member
which has to be accessed in template function back to private section
of Foo.
I don't like it cause I have to expose implementation details which is
what pimpl helps me not to do.
Can anyone think of more solutions to this problem? Maybe there is
a direct solution which allows somehow to keep the original
design and access pimpl members?
Thanks!
P.Krumins
I was playing around pimpl idiom and discovered that there is a problem
with it if a class member template function exists which has to access
private data, since only the forward declaration of pimpl class is
provided.
Example:
class Foo
{
private:
struct foo_impl;
foo_impl *pimpl;
public:
// ...
//
template <typename T>
T bar()
{
// bar() has to access private data which is located
// in pimpl.
// for example,
int id = pimpl->baz;
// ...
}
};
To allow the template be instantiated for any type is has to be
left in the interface of Foo class. But then it cannot access
pimpl->baz because pimpl has only been forward declared.
I have three solutions but I do not like any of them.
The first solution is to include or write the definition of
foo_impl class in the same file where Foo's interface is,
so Foo::foo_impl was defined.
I don't like because it would not reduce compile times and probably
will make client code to be recompiled since header file would have
changed since last compile and most tools for automatic compilation
look at modification times.
The second solution is to create a global function which takes
a reference to Foo and make this function a friend to Foo.
Example,
class Foo {
// ...
template <typename T>
friend int bar(Foo &foo);
// ...
};
and somewhere
template <typename T> int bar(Foo &foo) { return foo->impl->baz; }
As bar() is friend to Foo, it can access private pimpl.
I don't like this solution because i break interface of Foo, instead
of a convenient member function a global has to be added and an object
has to be passed to this function.
The third solution is the simplest, bring the particular private member
which has to be accessed in template function back to private section
of Foo.
I don't like it cause I have to expose implementation details which is
what pimpl helps me not to do.
Can anyone think of more solutions to this problem? Maybe there is
a direct solution which allows somehow to keep the original
design and access pimpl members?
Thanks!
P.Krumins