views:

113

answers:

2

The following template will decide if T is abstract with g++.

/**
   isAbstract<T>::result is 1 if T is abstract, 0 if otherwise.
 */
template<typename T>
class isAbstract
{
   class No { };
   class Yes { No no[3]; }; 

   template<class U> static No test( U (*)[1] ); // not defined
   template<class U> static Yes test( ... ); // not defined 

public:
   enum { result = sizeof( isAbstract<T>::template test<T>( 0 ) ) == sizeof(Yes) }; 
};

For example: struct myClass2 { virtual void f() {} }; struct myClass1 { virtual void f() = 0; };

bool twoAbstract = isAbstract<myClass2>::result;
bool oneAbstract = isAbstract<myClass1>::result;

However, it fails in visual studio 9.0 with the error:

error C2784: 'AiLive::isAbstract<T>::No AiLive::isAbstract<T>::test(U (*)[1])' : could not deduce template argument for 'U (*)[1]' from 'myClass2'

Does anyone have an idea of what the problem is and how to fix this?

MSDN Reports that they now have an is_abstract class since VS2008 as part of TR1 (inside the header type_traits). However, it seems to be missing from my installation.

PS. For reasons that are long and boring, I can't reimplement this via Boost.

Update

Also, tried replacing,

template<class U> static No test( U (*)[1] );

with each of,

template<class U> static No test( U (*x)[1] );
template<class U> static No test( U (*)() );
template<class U> static No test( U (*x)() );

and

template <typename U>
struct U2 : public U
{
   U2( U* ) {}
};

// Match if I can make a U2
template <typename U> static No test( U2<U> x  );

and

// Match if I can make a U2
template <typename U> static No test( U2<T> x  );

No luck - all say that template argument cannot be deduced for U.

A: 

Not sure as I've note done C++ for a while but can you use

template< typename  T, typename  U>
class isAbstract
{
   class No { };
   class Yes { No no[3]; }; 

   template<class U> static No test( U (*)[1] ); // not defined
   template<class U> static Yes test( ... ); // not defined 

public:
   enum { result = sizeof( isAbstract<T>::template test<T>( 0 ) ) == sizeof(Yes) }; 
};


bool twoAbstract = isAbstract<myClass2, SomeTypeU>::result;
Preet Sangha
I had a play around with this and couldn't get it to work. Basically, if SomeTypeU=myClass2 then its the same as the original problems. If SomeTypeU is any other type then the test is incorrect. Thanks for trying.
+1  A: 

This works for me in VC9:

template<typename T>
class isAbstract
{
    class No { };
    class Yes { No no[3]; }; 

    template<class U> static No test( U (*)[1] ); // not defined
    template<class U> static Yes test( ... ); // not defined 

public:
    enum { result = sizeof( test<T>( 0 ) ) == sizeof(Yes) }; 
};

Notice I just had to remove isAbstract<T>:: from the call to test.

Yuyo
Huh. Weird --- that's it! Thanks. Not sure why this is different between VC and gcc, or why the fully qualified name should give problems.