Re: Constraints => Traits
IR wrote:
Greg Herlihy wrote:
To use these templates for your purposes, just declare
CopyableTrait as shown below (no specialization is needed):
template<typename T>
class CopyableTrait
: public Trait< has_copy_member<T, T>::value>
{};
I have been struggling with this issue too. SFINAE works well when
you know the exact signature of the function, but...
CloneableTrait should (IMHO) also be true for polymorphic types:
struct A
{
virtual A* Clone() const;
};
struct B: public A
{
A* Clone() const;
};
But one could also write B using a covariant return type.
So the constraint on CloneableTrait<T> is not to have a
T* Clone() const function, but rather S* Clone() const, where S
is either T or one of it's base classes.
The program I posted requires that a virtual copy method declare a
covariant return type that matches the static type of object whose copy
member is being tested. And I would argue that any other return type
should disqualify the method as a "true" copy routine for the object.
And to some extent, CopyableTrait<T> should (still IMHO) be true for
any S Copy() const where S is publicly convertible to T (if this
leads to a split, my understanding is that the implementor of T is
the one who should be blamed).
However, no matter how hard I tortured that kind of code to try to
make it fit the SFINAE traits design, I couldn't manage it as of
today.
Managing to push SFINAE beyond the limit of having to know the exact
function signature would definitely allow some decent compile-time
reflection, but all the search I done on so far the subject yielded
no interesting results. :(
I managed to extend the original program to perform such a test. This
revised test (made somewhat messier by my changes) now returns "true"
when the declared return type of the object's copy method is either a
pointer to an object of the same class or a pointer to an object of one
of its base classes.
#include <iostream>
#include <ios>
#include <tr1/type_traits>
using std::tr1::is_base_of;
// Helper template classes
template < bool, class T1, class T2 > struct if_;
template < class T1, class T2 > struct
if_< true, T1, T2 >{ typedef T1 type; };
template < class T1, class T2 > struct
if_< false, T1, T2 >{ typedef T2 type; };
template < bool B > struct Bool;
template <> struct Bool<true> { char b[1]; };
template <> struct Bool<false> { char b[16]; };
// Test for covariant return type
template < class T1 >
struct MFTest
{
template <class T2>
static Bool< is_base_of<T2, T1>::value>
f( T2* (T1::*)() const);
};
template< class T1, class T2 >
struct has_copy_member {
static const bool value = false; };
template< class T>
struct has_copy_member<T,
typename if_<sizeof( MFTest<T>::f(&T::copy))
== sizeof(Bool<true>),
T, void >::type >
{ static const bool value = true; };
// Test classes
struct A { virtual A* copy() const; };
struct B {};
struct C : public A { virtual A* copy() const; };
struct D { B* copy() const; };
struct E : public A { E* copy() const; };
using std::cout;
int main()
{
cout << std::boolalpha;
cout << "A has copy member? ";
cout << has_copy_member<A, A>::value << "\n";
cout << "B has copy member? ";
cout << has_copy_member<B, B>::value << "\n";
cout << "C has copy member? ";
cout << has_copy_member<C, C>::value << "\n";
cout << "D has copy member? ";
cout << has_copy_member<D, D>::value << "\n";
cout << "E has copy member? ";
cout << has_copy_member<E, E>::value << "\n";
}
Program Output:
A has copy member? true
B has copy member? false
C has copy member? true
D has copy member? false
E has copy member? true
Greg
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]