/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // @author: Andrei Alexandrescu #pragma once #include #include #include #include #include #include #define FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(classname, type_name) \ template \ struct classname##__folly_traits_impl__ { \ template \ static constexpr bool test(typename UTheClass_::type_name*) { \ return true; \ } \ template \ static constexpr bool test(...) { \ return false; \ } \ }; \ template \ using classname = typename std::conditional< \ classname##__folly_traits_impl__::template test( \ nullptr), \ std::true_type, \ std::false_type>::type #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 { template struct tag_t {}; #if __cplusplus >= 201703L template inline constexpr tag_t tag; #endif #if __cpp_lib_bool_constant || _MSC_VER using std::bool_constant; #else // mimic: std::bool_constant, C++17 template using bool_constant = std::integral_constant; #endif template using index_constant = std::integral_constant; namespace detail { /** * A type trait to check if a given type is an instantiation of a class * template. * * Note that this only works with template type parameters. It does not work * with non-type template parameters, template template parameters, or alias * templates. */ template