Re: Factoring SFINAE tests
On Sep 8, 2:17 pm, Greg Herlihy <gre...@pacbell.net> wrote:
On 9/7/07 3:42 PM, in article
46e1d3f5$0$28521$5a62a...@per-qv1-newsreader-01.iinet.net.au, "Gianni
Mariani" <gi3nos...@mariani.ws> wrote:
Below is an attempt to factorize the "SFINAE" idiom. I have tried it on
three compilers and they all complain. As far as I can tell, it's valid
code. The questions are, are the compilers right to reject the code or
is the code right and why ? and has anyone successfully mastered the act
of factorizing SFINAE?
----------------------------------------------------------------------
template <template <typename> class w_Test, typename w_Type>
class sfinae_test
{
typedef char (&false_value)[1];
typedef char (&true_value)[2];
struct base {};
struct derived : base {};
static derived & make_derived();
static w_Type& make_test();
template <bool i>
struct H
{
};
template <typename Z>
static false_value func( Z &, base & );
template <typename Z>
static true_value func(Z&, derived&, typename w_Test<Z>::type* =0 );
public:
static const bool value =
sizeof(func(make_test(), make_derived())) == sizeof(true_value);
};
// some tests
// is_defined_test will fail if T is not defined
template <typename T> class is_defined_test
{
typedef char (&type)[ sizeof( T ) ];
};
// has_member_orange will fail if T had no orange
template <typename T> class has_member_orange
{
static T& make_T();
public:
typedef char (&type)[ sizeof( make_T().orange ) ];
};
There is no example of SFINAE ("substitution failure is not an error") in
the this program; both has_member_orange<A> and is_defined_test<B> match
func()'s second parameter:
typename w_Test<Z>::type
because both template classes do declare an interior typedef named "type".
Now, the compiler does run into trouble instantiating has_member_orange<A>
and is_defined_test<B> (because the "type" typedef is ill-formed)- but this
error occurs only after the type deduction needed to select func() has
already been performed. So the ill-formed template specialization error
comes too late for SFINAE to help - so the result is a compile-time error.
Greg
Hi to all,
sorry for bringing this out again but it was just too interesting.
I did some research to understand what you guys were talking about and
I got to this link
http://aszt.inf.elte.hu/~gsd/slides/Introspection.ppt
I think it is a presentation of a book...
It's quite cryptic but I used it as a starting point. Hope it's not
plagiarizing... :-)
Obviously I dind't get anywhere interesting because I miserably failed
to "factorize" these idioms with templates, inheritance, etc...
But I've done some things that I did not know were possible with
macros ( probably I just reinvented the wheel )...
Please let me know what you think and if there is a better way of
doing it. I've just done some small trivial testing...
Bye,
Francesco
#include <iostream>
//----------------------------------------------------------------------------------------------------
namespace trg
{
// just a namespace for my own small utilities
//----------------------------------------------------------------------------------------------------
typedef char ( & tYes ) [ 1 ];
typedef char ( & tNo ) [ 2 ];
//----------------------------------------------------------------------------------------------------
// struct CTypeEnable
//----------------------------------------------------------------------------------------------------
// this is just boost::enable_if plagiarized ;-)
template< typename T, bool KCond >
struct CTypeEnable
{
typedef T tResult;
};
//
template< typename T >
struct CTypeEnable< T, false >
{};
//----------------------------------------------------------------------------------------------------
// TRG_SFINAE_CORE_CHECK_GEN_DEF
//----------------------------------------------------------------------------------------------------
#define TRG_SFINAE_CORE_CHECK_GEN_DEF( ARG_Prefix, ARG_TemplType,
ARG_Cond, ARG_RetType ) \
template< typename ARG_TemplType > \
ARG_Prefix typename trg::CTypeEnable< ARG_RetType, ARG_Cond
::tResult SfinaeCoreCheck( ARG_TemplType * );
//----------------------------------------------------------------------------------------------------
// TRG_SFINAE_CORE_CHECK_GEN_DEF
//----------------------------------------------------------------------------------------------------
#define TRG_SFINAE_CORE_CHECK_STD_DEF( ARG_TemplType,
ARG_SizeofCond ) \
TRG_SFINAE_CORE_CHECK_GEN_DEF( static, ARG_TemplType,
sizeof( ARG_SizeofCond ), trg::tYes )
//----------------------------------------------------------------------------------------------------
// TRG_SFINAE_CHECK_DEF
//----------------------------------------------------------------------------------------------------
#define TRG_SFINAE_CHECK_DEF( ARG_CheckName, ARG_InnerTemplType,
ARG_Feature ) \
template< typename T > \
struct CSfinaeCheck_ ## ARG_CheckName \
{ \
TRG_SFINAE_CORE_CHECK_STD_DEF( ARG_InnerTemplType,
ARG_Feature ); \
\
static trg::tNo SfinaeCoreCheck( ... ); \
\
enum { kResult = sizeof( SfinaeCoreCheck( static_cast< T *
( NULL ) ) ) == sizeof( trg::tYes ) }; \
};
//----------------------------------------------------------------------------------------------------
// TRG_SFINAE_CHECK "SPECIALIZATIONS"
//----------------------------------------------------------------------------------------------------
#define TRG_SFINAE_CHECK_MEMBER_EXIST( ARG_MemberName ) \
TRG_SFINAE_CHECK_DEF( MemberExist_ ## ARG_MemberName, T2,
&T2::ARG_MemberName )
#define TRG_SFINAE_CHECK_INNER_TYPE_EXIST( ARG_Typename ) \
TRG_SFINAE_CHECK_DEF( InnerTypeExist_ ## ARG_Typename, T2, typename
T2::ARG_Typename )
#define TRG_SFINAE_CHECK_IS_CLASS \
TRG_SFINAE_CHECK_DEF( IsClass, T2, int T2::* )
TRG_SFINAE_CHECK_IS_CLASS;
//----------------------------------------------------------------------------------------------------
// TRG_OVERLOAD_CHECK_DEF
//----------------------------------------------------------------------------------------------------
#define TRG_OVERLOAD_CHECK_DEF( ARG_CheckName, ARG_TemplType,
ARG_TestType, ARG_Object ) \
template< typename ARG_TemplType > \
struct COverloadCheck_ ## ARG_CheckName \
{ \
static trg::tYes OverloadCheck( ARG_TestType ); \
static trg::tNo OverloadCheck( ... ); \
enum { kResult = sizeof( OverloadCheck( ARG_Object ) ) ==
sizeof( trg::tYes ) }; \
}
//----------------------------------------------------------------------------------------------------
// struct CConditionalCheck
//----------------------------------------------------------------------------------------------------
template< template< typename > class TCheck, typename T, bool KCond >
struct CConditionalCheck
{
enum { kResult = false };
};
//
template< template< typename > class TCheck, typename T >
struct CConditionalCheck< TCheck, T, true >
{
enum { kResult = TCheck< T >::kResult };
};
//----------------------------------------------------------------------------------------------------
} // namespace trg
//----------------------------------------------------------------------------------------------------
struct A
{
void Tester( int, double );
};
struct B
{
typedef int Tester;
};
struct C
{
static void Tester( int, double );
};
struct D
{
void Tester( float );
};
TRG_SFINAE_CHECK_MEMBER_EXIST( Tester );
TRG_SFINAE_CHECK_INNER_TYPE_EXIST( Tester );
TRG_OVERLOAD_CHECK_DEF( TesterVoidIntDouble, T, void ( T::* )( int,
double ), &T::Tester );
int main()
{
std::cout << "+ A\n";
std::cout << CSfinaeCheck_MemberExist_Tester< A >::kResult <<
std::endl;
std::cout << CSfinaeCheck_InnerTypeExist_Tester< A >::kResult <<
std::endl;
std::cout << trg::CConditionalCheck<
COverloadCheck_TesterVoidIntDouble, A,
CSfinaeCheck_MemberExist_Tester< A >::kResult >::kResult << std::endl;
std::cout << "+ B\n";
std::cout << CSfinaeCheck_MemberExist_Tester< B >::kResult <<
std::endl;
std::cout << CSfinaeCheck_InnerTypeExist_Tester< B >::kResult <<
std::endl;
std::cout << trg::CConditionalCheck<
COverloadCheck_TesterVoidIntDouble, B,
CSfinaeCheck_MemberExist_Tester< B >::kResult >::kResult << std::endl;
std::cout << "+ C\n";
std::cout << CSfinaeCheck_MemberExist_Tester< C >::kResult <<
std::endl;
std::cout << CSfinaeCheck_InnerTypeExist_Tester< C >::kResult <<
std::endl;
std::cout << trg::CConditionalCheck<
COverloadCheck_TesterVoidIntDouble, C,
CSfinaeCheck_MemberExist_Tester< C >::kResult >::kResult << std::endl;
std::cout << "+ D\n";
std::cout << CSfinaeCheck_MemberExist_Tester< D >::kResult <<
std::endl;
std::cout << CSfinaeCheck_InnerTypeExist_Tester< D >::kResult <<
std::endl;
std::cout << trg::CConditionalCheck<
COverloadCheck_TesterVoidIntDouble, D,
CSfinaeCheck_MemberExist_Tester< D >::kResult >::kResult << std::endl;
}