summaryrefslogtreecommitdiff
path: root/boost/convert/detail/is_callable.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/convert/detail/is_callable.hpp')
-rw-r--r--boost/convert/detail/is_callable.hpp100
1 files changed, 100 insertions, 0 deletions
diff --git a/boost/convert/detail/is_callable.hpp b/boost/convert/detail/is_callable.hpp
new file mode 100644
index 0000000000..d516fdc05b
--- /dev/null
+++ b/boost/convert/detail/is_callable.hpp
@@ -0,0 +1,100 @@
+// Copyright (c) 2009-2014 Vladimir Batov.
+// Use, modification and distribution are subject to the Boost Software License,
+// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
+
+#ifndef BOOST_CONVERT_IS_CALLABLE_HPP
+#define BOOST_CONVERT_IS_CALLABLE_HPP
+
+#include <boost/convert/detail/has_member.hpp>
+
+namespace boost { namespace cnv { namespace detail
+{
+ typedef ::boost::type_traits::yes_type yes_type;
+ typedef ::boost::type_traits:: no_type no_type;
+
+ struct not_found {};
+ struct void_return_substitute {};
+
+ // The overloaded comma operator only kicks in for U != void essentially short-circuiting
+ // itself ineffective. Otherwise, when U=void, the standard op,() kicks in and returns
+ // 'void_return_substitute'.
+ template<typename U> U const& operator, (U const&, void_return_substitute);
+ template<typename U> U& operator, (U&, void_return_substitute);
+
+ template <typename src, typename dst> struct match_const { typedef dst type; };
+ template <typename src, typename dst> struct match_const<src const, dst> { typedef dst const type; };
+
+ template<typename T, typename return_type>
+ struct redirect
+ {
+ static no_type test (...);
+ static yes_type test (return_type);
+ };
+
+ template<typename T>
+ struct redirect<T, void>
+ {
+ static yes_type test (...);
+ static no_type test (not_found);
+ };
+}}}
+
+// No-args case needs to be implemented differently and has not been implemented yet.
+// template <typename R>
+// struct check<true, R ()>
+
+// C1. Need to find some unique/ugly names so that they do not clash if this macro is
+// used inside some other template class;
+// C2. Body of the function is not actually used anywhere.
+// However, Intel C++ compiler treats it as an error. So, we provide the body.
+
+#define BOOST_DECLARE_IS_CALLABLE(__trait_name__, __member_name__) \
+ \
+template <typename __boost_is_callable_T__, typename __boost_is_callable_signature__> \
+class __trait_name__ \
+{ \
+ typedef __boost_is_callable_T__ class_type; /*C1*/ \
+ typedef __boost_is_callable_signature__ signature; /*C1*/ \
+ typedef boost::cnv::detail::not_found not_found; \
+ \
+ BOOST_DECLARE_HAS_MEMBER(has_member, __member_name__); \
+ \
+ struct mixin : public class_type \
+ { \
+ using class_type::__member_name__; \
+ not_found __member_name__(...) const { return not_found(); /*C2*/} \
+ }; \
+ \
+ typedef typename boost::cnv::detail::match_const<class_type, mixin>::type* mixin_ptr; \
+ \
+ template <bool has, typename F> struct check { static bool const value = false; }; \
+ \
+ template <typename Arg1, typename R> \
+ struct check<true, R (Arg1)> \
+ { \
+ typedef typename boost::decay<Arg1>::type* a1; \
+ \
+ static bool const value = sizeof(boost::type_traits::yes_type) \
+ == sizeof(boost::cnv::detail::redirect<class_type, R>::test( \
+ (mixin_ptr(0)->__member_name__(*a1(0)), \
+ boost::cnv::detail::void_return_substitute()))); \
+ }; \
+ template <typename Arg1, typename Arg2, typename R> \
+ struct check<true, R (Arg1, Arg2)> \
+ { \
+ typedef typename boost::decay<Arg1>::type* a1; \
+ typedef typename boost::decay<Arg2>::type* a2; \
+ \
+ static bool const value = sizeof(boost::type_traits::yes_type) \
+ == sizeof(boost::cnv::detail::redirect<class_type, R>::test( \
+ (mixin_ptr(0)->__member_name__(*a1(0), *a2(0)), \
+ boost::cnv::detail::void_return_substitute()))); \
+ }; \
+ \
+ public: \
+ \
+ /* Check the existence of __member_name__ first, then the signature. */ \
+ static bool const value = check<has_member<class_type>::value, signature>::value; \
+}
+
+#endif // BOOST_CONVERT_IS_CALLABLE_HPP