From: Yedidya Feldblum Date: Mon, 2 Jan 2017 06:25:37 +0000 (-0800) Subject: Move the traits factories up, and remove X-Git-Tag: v2017.03.06.00~144 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=ca73efa8df8aa374b945efde9f35f6de85de619a;p=folly.git Move the traits factories up, and remove Summary: [Folly] Move the traits factories up, and remove ``. Also, they now generate aliases to the types aliased by `std::true_type` and `std::false_type`. So now the API is entirely compatible with the requirements of `std::integral_constant` (because it is `std::integral_constant`). Reviewed By: wqfish Differential Revision: D4375944 fbshipit-source-id: dfd41283f13d793f7fc1f173590cd93cdee39a10 --- diff --git a/folly/Traits.h b/folly/Traits.h index 999a7a25..a038b18c 100644 --- a/folly/Traits.h +++ b/folly/Traits.h @@ -37,7 +37,96 @@ #endif #include -#include + +#define FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(classname, type_name) \ + template \ + struct classname##__folly_traits_impl__ { \ + template \ + static std::true_type test(typename UTheClass_::type_name*); \ + template \ + static std::false_type test(...); \ + }; \ + template \ + using classname = decltype( \ + classname##__folly_traits_impl__::template test( \ + nullptr)) + +#define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, cv_qual) \ + template \ + struct classname##__folly_traits_impl__< \ + TTheClass_, \ + RTheReturn_(TTheArgs_...) cv_qual> { \ + template < \ + typename UTheClass_, \ + RTheReturn_ (UTheClass_::*)(TTheArgs_...) cv_qual> \ + struct sfinae {}; \ + template \ + static std::true_type test(sfinae*); \ + template \ + static std::false_type test(...); \ + } + +/* + * The FOLLY_CREATE_HAS_MEMBER_FN_TRAITS is used to create traits + * classes that check for the existence of a member function with + * a given name and signature. It currently does not support + * checking for inherited members. + * + * Such classes receive two template parameters: the class to be checked + * and the signature of the member function. A static boolean field + * named `value` (which is also constexpr) tells whether such member + * function exists. + * + * Each traits class created is bound only to the member name, not to + * its signature nor to the type of the class containing it. + * + * Say you need to know if a given class has a member function named + * `test` with the following signature: + * + * int test() const; + * + * You'd need this macro to create a traits class to check for a member + * named `test`, and then use this traits class to check for the signature: + * + * namespace { + * + * FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_test_traits, test); + * + * } // unnamed-namespace + * + * void some_func() { + * cout << "Does class Foo have a member int test() const? " + * << boolalpha << has_test_traits::value; + * } + * + * You can use the same traits class to test for a completely different + * signature, on a completely different class, as long as the member name + * is the same: + * + * void some_func() { + * cout << "Does class Foo have a member int test()? " + * << boolalpha << has_test_traits::value; + * cout << "Does class Foo have a member int test() const? " + * << boolalpha << has_test_traits::value; + * cout << "Does class Bar have a member double test(const string&, long)? " + * << boolalpha << has_test_traits::value; + * } + * + * @author: Marcelo Juchem + */ +#define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(classname, func_name) \ + template \ + struct classname##__folly_traits_impl__; \ + FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, ); \ + FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, const); \ + FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL( \ + classname, func_name, /* nolint */ volatile); \ + FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL( \ + classname, func_name, /* nolint */ volatile const); \ + template \ + using classname = \ + decltype(classname##__folly_traits_impl__:: \ + template test(nullptr)) namespace folly { @@ -91,7 +180,7 @@ namespace folly { namespace traits_detail { #define FOLLY_HAS_TRUE_XXX(name) \ - BOOST_MPL_HAS_XXX_TRAIT_DEF(name) \ + FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_##name, name); \ template \ struct name##_is_true : std::is_same {}; \ template \ @@ -597,88 +686,6 @@ FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::function) FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(boost::shared_ptr) #endif -#define FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(classname, type_name) \ - template \ - struct classname { \ - template \ - constexpr static bool test(typename C::type_name*) { return true; } \ - template \ - constexpr static bool test(...) { return false; } \ - constexpr static bool value = test(nullptr); \ - } - -#define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, cv_qual) \ - template \ - class classname { \ - template < \ - typename UTheClass_, RTheReturn_ (UTheClass_::*)(TTheArgs_...) cv_qual \ - > struct sfinae {}; \ - template \ - constexpr static bool test(sfinae*) \ - { return true; } \ - template \ - constexpr static bool test(...) { return false; } \ - public: \ - constexpr static bool value = test(nullptr); \ - } - -/* - * The FOLLY_CREATE_HAS_MEMBER_FN_TRAITS is used to create traits - * classes that check for the existence of a member function with - * a given name and signature. It currently does not support - * checking for inherited members. - * - * Such classes receive two template parameters: the class to be checked - * and the signature of the member function. A static boolean field - * named `value` (which is also constexpr) tells whether such member - * function exists. - * - * Each traits class created is bound only to the member name, not to - * its signature nor to the type of the class containing it. - * - * Say you need to know if a given class has a member function named - * `test` with the following signature: - * - * int test() const; - * - * You'd need this macro to create a traits class to check for a member - * named `test`, and then use this traits class to check for the signature: - * - * namespace { - * - * FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_test_traits, test); - * - * } // unnamed-namespace - * - * void some_func() { - * cout << "Does class Foo have a member int test() const? " - * << boolalpha << has_test_traits::value; - * } - * - * You can use the same traits class to test for a completely different - * signature, on a completely different class, as long as the member name - * is the same: - * - * void some_func() { - * cout << "Does class Foo have a member int test()? " - * << boolalpha << has_test_traits::value; - * cout << "Does class Foo have a member int test() const? " - * << boolalpha << has_test_traits::value; - * cout << "Does class Bar have a member double test(const string&, long)? " - * << boolalpha << has_test_traits::value; - * } - * - * @author: Marcelo Juchem - */ -#define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(classname, func_name) \ - template class classname; \ - FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, ); \ - FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, const); \ - FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL( \ - classname, func_name, /* nolint */ volatile); \ - FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL( \ - classname, func_name, /* nolint */ volatile const) - /* Some combinations of compilers and C++ libraries make __int128 and * unsigned __int128 available but do not correctly define their standard type * traits. diff --git a/folly/test/TraitsTest.cpp b/folly/test/TraitsTest.cpp index a5f1a052..8658a58a 100644 --- a/folly/test/TraitsTest.cpp +++ b/folly/test/TraitsTest.cpp @@ -27,6 +27,24 @@ using namespace folly; using namespace std; +namespace { + +FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_member_type_x, x); +} + +TEST(Traits, has_member_type) { + struct membership_no {}; + struct membership_yes { + using x = void; + }; + + EXPECT_TRUE((is_same>::value)); + EXPECT_TRUE((is_same>::value)); +} + +// Note: FOLLY_CREATE_HAS_MEMBER_FN_TRAITS tests are in +// folly/test/HasMemberFnTraitsTest.cpp. + struct T1 {}; // old-style IsRelocatable, below struct T2 {}; // old-style IsRelocatable, below struct T3 { typedef std::true_type IsRelocatable; }; @@ -198,12 +216,3 @@ TEST(Traits, actuallyRelocatable) { testIsRelocatable>(5, 'g'); } - -struct membership_no {}; -struct membership_yes { using x = void; }; -FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_member_type_x, x); - -TEST(Traits, has_member_type) { - EXPECT_FALSE(bool(has_member_type_x::value)); - EXPECT_TRUE(bool(has_member_type_x::value)); -}