Friend declaration not accepted by MSVC
In the code below the commented friend declaration is not accepted by MSVC 7.1.
<code>
// Copyright (c) Alf P. Steinbach, 2009.
#ifndef PROGROCK_CPPX_POINTERS_ZPTR_H
#define PROGROCK_CPPX_POINTERS_ZPTR_H
// #include <progrock/cppx/pointers/ZPtr.h>
#include <progrock/cppx/no_sillywarnings_please.h>
#include <progrock/cppx/exception_util.h> // throwX
#include <progrock/cppx/static_assert.h> // CPPX_IS_OVERRIDE_OFxxx
#include <assert.h>
#include <memory>
namespace progrock{ namespace cppx{
//TODO: Implement for real.
template< class T > class ZPtr;
namespace zptr{ class Referent; class Callback; }
class ZPtrMicrosoftVisualCppWorkaround
{
template< class T > friend class ZPtr;
private:
static void deleteSelfNoCallback( zptr::Referent& r );
template< class T >
static T* create( zptr::Callback& aCallback )
{ return new T( aCallback ); }
template< class T, class A1 >
static T* create( zptr::Callback& aCallback, A1 const& a1 )
{ return new T( aCallback, a1 ); }
template< class T, class A1, class A2 >
static T* create( zptr::Callback& aCallback, A1 const& a1, A2 const& a2 )
{ return new T( aCallback, a1, a2 ); }
template< class T, class A1, class A2, class A3 >
static T* create( zptr::Callback& aCallback, A1 const& a1, A2 const&
a2, A3 const& a3 )
{ return new T( aCallback, a1, a2, a3 ); }
};
namespace zptr {
class XThrower
{
public:
typedef std::auto_ptr<XThrower> AutoPtr;
virtual ~XThrower() {}
virtual bool throwX() const
{
return cppx::throwX( "cppx::ZPtr: referent has been destroyed" );
}
};
class Callback
{
public:
virtual ~Callback() {}
virtual void destroyAnyCompleteMeAndSetAccessX( XThrower::AutoPtr )
= 0;
};
class Referent
{
//template< class T > friend class cppx::ZPtr;
friend class ZPtrMicrosoftVisualCppWorkaround; // MSVC 7.1 can't
handle the direct friend.
typedef Referent ThisClass;
private:
Callback* myCallback;
Referent( ThisClass const& ); // No such.
ThisClass& operator=( ThisClass const& ); // No such.
void deleteSelfNoCallback()
{
delete this;
}
static void* operator new( size_t nBytes )
{
return ::new char[nBytes];
}
static void operator delete( void* p )
{
::delete[] static_cast<char*>( p );
}
protected:
virtual ~Referent() {}
template< class ExceptionType >
void handleUnrecoverableFailure(
ExceptionType const& x,
XThrower::AutoPtr xThrower = XThrower::AutoPtr( new
XThrower )
)
{
myCallback->destroyAnyCompleteMeAndSetAccessX( xThrower );
throw x;
}
public:
Referent( Callback& aCallback ): myCallback( &aCallback ) {}
};
enum DefaultConstructed {};
} // namespace zptr
inline void ZPtrMicrosoftVisualCppWorkaround::deleteSelfNoCallback(
zptr::Referent& r )
{
r.deleteSelfNoCallback();
}
template< typename T >
class ZPtr
: private zptr::Callback
{
typedef ZPtr ThisClass;
private:
T* myReferent; // 0 while the T constructs.
zptr::XThrower::AutoPtr myXAction;
ZPtr( ThisClass const& ); // No such.
ThisClass& operator=( ThisClass const& ); // No such.
void deleteReferent()
{
if( myReferent == 0 ) { return; }
try
{
ZPtrMicrosoftVisualCppWorkaround::deleteSelfNoCallback(
*myReferent );
}
catch( ... )
{
assert( "cppx::ZPtr: referent threw exception when deleted" &&
false );
}
myReferent = 0;
}
virtual void destroyAnyCompleteMeAndSetAccessX( zptr::XThrower::AutoPtr
xThrower )
{
CPPX_IS_OVERRIDE_OF_1ARG(
zptr::Callback::destroyAnyCompleteMeAndSetAccessX, xThrower );
assert( xThrower.get() != 0 );
assert( myXAction.get() == 0 );
deleteReferent();
myXAction = xThrower;
}
public:
ZPtr( zptr::DefaultConstructed )
: myReferent( 0 )
{
myReferent = ZPtrMicrosoftVisualCppWorkaround::create<T>( *this );
}
template< class A1 >
ZPtr( A1 const& a1 )
: myReferent( 0 )
{
myReferent = ZPtrMicrosoftVisualCppWorkaround::create<T>( *this, a1 );
}
template< class A1, class A2 >
ZPtr( A1 const& a1, A2 const& a2 )
: myReferent( 0 )
{
myReferent = ZPtrMicrosoftVisualCppWorkaround::create<T>( *this,
a1, a2 );
}
template< class A1, class A2, class A3 >
ZPtr( A1 const& a1, A2 const& a2, A3 const a3 )
: myReferent( 0 )
{
myReferent = ZPtrMicrosoftVisualCppWorkaround::create<T>( *this,
a1, a2, a3 );
}
~ZPtr()
{
deleteReferent();
}
bool isVoid() const
{
return (myReferent == 0);
}
void throwIfVoid() const
{
if( isVoid() )
{
assert( myXAction.get() != 0 );
myXAction->throwX();
assert( "Execution should never reach this point." && 0 );
}
}
T* operator->() const
{
throwIfVoid();
return myReferent;
}
};
}} // namespace progrock::cppx
#endif
</code>
I wonder if there's any better workaround than the kludge shown?
Also, is there a problem with this friend declaration with any other
compiler/version (the same kind of declaration worked fine with g++ and Comeau)?
Cheers, & TIA.,
- Alf