/ * We define the HasF metafunction, which allows us to determine the presence of the f () function in any class. * /
DECLARE_IS_VALID_EXPRESSION (
HasF,
( ( U * ) NULL ) - > f ( ) / * This expression is compiled only if U :: f () * / ) is present ;
')
struct Foo { void f ( ) ; } ;
struct Bar { } ;
BOOST_STATIC_ASSERT ( HasF <A> :: value ) ; / * The HasF <A> :: value constant will be true * /
BOOST_STATIC_ASSERT ( ! HasF < B > :: value ) ; / * Here the HasF constant <A> :: value will be false * /
$ define DECLARE_IS_VALID_EXPRESSION ( NAME, U_BASED_RUNTIME_EXPRESSION ) \
template < class T > \
struct NAME \
{ \
/ * We need some type that is not exactly T for comparison * / \
struct CDummy { } ; \
\
/ * This overload will work only when U_BASED_RUNTIME_EXPRESSION does not contain "errors" \
** Otherwise, this overload will be ignored according to SFINAE. * / \
template < typename U > \
static decltype ( U_BASED_RUNTIME_EXPRESSION ) F ( void * ) ; \
\
/ * But this overload is always present, but its priority is lower, because the ellipsis * / \
template < typename U > \
static CDummy F ( ... ) ; \
\
/ * This typedef might not have been, but without it, this class does not work correctly :( \
** (I take this opportunity to say hello to testers from the Visual Studio command) * / \
typedef decltype ( F < T > ( nullptr ) ) \
TDummy ; \
\
enum \
{ \
/ * value will be 1 if U_BASED_RUNTIME_EXPRESSION does not contain "errors" and 0 otherwise \
** Why? \
** If there are no "errors", then both versions of F are present, and F <T> (nullptr) selects one, \
** in which there is no ellipsis, i.e. with our test expression, and its return type
** not CDummy, because CDummy is declared locally. \
** If there are "errors", then option F with the tested expression will be thrown out, and, \
** respectively, F <T> (nullptr) will select the second overload (which returns CDummy) * / \
value = ! boost :: is_same < CDummy, TDummy > :: value \
} ; \
} ;
/ * Specifies the IsStreamSerializationSupported metafunction, which returns
** true if the argument supports input / output through threads * /
DECLARE_IS_VALID_EXPRESSION (
IsStreamSerializationSupported,
( ( std :: cout << * ( U * ) NULL ) , ( std :: cin >> * ( U * ) NULL ) ) ) ;
/ * double supports I / O through out-of-box * /
BOOST_STATIC_ASSERT ( IsStreamSerializationSupported < double > :: value ) ;
struct Foo { } ;
/ * But Foo I / O through streams does not support :( * /
BOOST_STATIC_ASSERT ( ! IsStreamSerializationSupported < Foo > :: value ) ;
struct Bar { } ;
template < class TChar, class Traits >
std :: basic_ostream < TChar, Traits > & operator << (
std :: basic_ostream < TChar, Traits > & , const Bar & ) ;
template < class TChar, class Traits >
std :: basic_istream < TChar, Traits > & operator >> (
std :: basic_istream < TChar, Traits > & , Bar & ) ;
/ * Bar supports in / out through streams, since The corresponding operators are defined. * /
BOOST_STATIC_ASSERT ( IsStreamSerializationSupported < Bar > :: value ) ;
Source: https://habr.com/ru/post/112239/
All Articles