Re: C++ language: Cloneable classes
On 10 Maj, 22:13, Daniel Kr?gler <daniel.krueg...@googlemail.com>
wrote:
Still, one thing bothers me.. The static assertion "is_base_of" should
stay, but it would be nice to also be able to use a normal Derived*
instead of some smart ptr type. Can that be achieved simply?
class X : public Cloneable<X,X*>, public NaturallyCloneable<X> {};
This is not so hard to solve given Boost's type-traits.
In the following code I also replaced the inner
BOOST_STATIC_ASSERT of the clone template by a SFINAE
technique and I allowed for cv-qualified return types:
template<typename T>
struct RemoveElementType {
typedef typename T::element_type type;
};
template<typename Target, typename PtrPolicy>
struct MatchingPtrs : boost::integral_constant<bool,
boost::is_base_of<Target, typename boost::remove_cv<
typename boost::mpl::if_<
boost::is_pointer<PtrPolicy>,
boost::remove_pointer<PtrPolicy>,
RemoveElementType<PtrPolicy>
>::type::type>::type>::value> {
};
template < typename Derived, typename DefaultPtrPolicy =
std::auto_ptr<Derived> >
class Cloneable : public virtual CloneableBase
{
public:
BOOST_STATIC_ASSERT(( MatchingPtrs<Derived,
DefaultPtrPolicy>::value ));
[...]
I figure there are 3 requirements for PtrPolicy:
1. Construct from Derived*
2. Dereferences (operator*) to a type which is base of Derived
3. operator-> returns a type which is base of Derived
PtrPolicy does not need to contain a typename element_type; only needs
to provide the above 3 requirements
For that I propose a concept Pointer; It's the first time I'm having
to do with writing concept requirements, so I don't even know if
that's the right way to do it, but seems to work for the example at
the bottom ;-)
[code]
#include <boost/concept_check.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>
namespace {
/** Type deduction will fail unless the arguments have the same type.
*/
template < typename Type >
inline void same_type( const volatile Type&, const volatile Type& ) {}
/** Type deduction will fail unless the pointers have the same type.
*/
template < typename Type >
inline void same_type_ptr( const volatile Type*, const volatile
Type* ) {}
/** Type deduction will fail unless Base is base of Derived. */
template < typename Base, typename Derived >
inline void base_of_type( const volatile Base&, const volatile
Derived& )
{
BOOST_STATIC_ASSERT(( boost::is_base_of<Base,Derived>::value ));
}
/** Type deduction will fail unless Base is base of Derived. */
template < typename Base, typename Derived >
inline void base_of_type_ptr( const volatile Base*, const volatile
Derived* )
{
BOOST_STATIC_ASSERT(( boost::is_base_of<Base,Derived>::value ));
}
} // namespace
/////////////////////////////////////////////////////////////////////////////
/** Pointer concept. */
template < typename Type, typename Ptr >
struct Pointer
{
void constraints()
{
Ptr p( pType_ );
base_of_type( *ptr_, type_ );
base_of_type_ptr( ptr_.operator->(), pType_ );
}
private:
Type& type_;
Type* pType_;
Ptr& ptr_;
};
/** Pointer concept. Specialization for classic pointers. */
template < typename Type, typename Base >
struct Pointer<Type,Base*>
{
void constraints()
{
Base* p( pType_ );
p = p; // avoid unused warning
}
private:
Type* pType_;
};
[/code]
And now in Cloneable<>:
[code]
template < typename Derived, typename DefaultPtrPolicy =
std::auto_ptr<Derived> >
class Cloneable : public virtual CloneableBase
{
BOOST_CLASS_REQUIRE2( Derived, DefaultPtrPolicy, , Pointer );
[...]
/** @safety aCI */
template < typename OtherPtrPolicy >
OtherPtrPolicy clone() const
{
boost::function_requires< Pointer<Derived,OtherPtrPolicy> >();
[...]
[/code]
And the example used previously with some extras:
[code]
class A : public Cloneable<A> {}; // abstract base for B and C
class B : public A, public NaturallyCloneable<B> {};
class C : public A { virtual A* doClone() const { return new C; } };
class X : public Cloneable<X,X*>, public NaturallyCloneable<X> {};
class Y : public A, public Cloneable< Y, boost::shared_ptr<A> >,
public NaturallyCloneable<Y> {};
// for testing Pointer concept:
template < typename Type, typename Ptr >
void f()
{
boost::function_requires< Pointer<Type,Ptr> >();
}
// for testing Pointer concept:
template < typename Type, typename Ptr >
class Z
{
BOOST_CLASS_REQUIRE2( Type, Ptr, , Pointer );
};
int main()
{
f<A,A::SmartPtr>();
f<X,X::SmartPtr>();
// f<A,B>(); // error
f<B,A*>();
// f<A,B*>(); // error
f< Y, boost::shared_ptr<A> >();
Z<A,A::SmartPtr>();
Z<X,X::SmartPtr>();
// Z<A,B>(); // error
Z<B,A*>();
// Z<A,B*>(); // error
Z< Y, boost::shared_ptr<A> >();
//A a; // error: abstract type
B b;
C c;
b.clone();
c.clone();
b.clone< boost::shared_ptr<A> >();
c.clone< boost::shared_ptr<A> >();
c.clone< boost::shared_ptr<const volatile A> >();
b.clone< A* >();
c.clone< const A* >();
X x;
x.clone();
}
[/code]
I've learned so much from this discussion, and I feel there's much
ahead of me too ;-D
Cheers
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]