The BOOST_DECLARE_IS_CALLABLE macro extends the functionality provided by BOOST_DECLARE_HAS_MEMBER and allows to declare a trait which would then let introspect the existence of a named class member function callable with the supplied signature.
For example, the following declarations introduce local::can_call_funop
and local::can_call_func
traits:
namespace { namespace local { BOOST_DECLARE_IS_CALLABLE(can_call_funop, operator()); BOOST_DECLARE_IS_CALLABLE(can_call_func, func); }}
The traits allow to test if the supplied class has respectively operator()
and func()
member functions callable with the specified signature:
namespace { namespace callable { struct test1 { int operator()(double, std::string) { return 0; }}; struct test2 { void operator()(double, std::string) {}}; struct test3 { void operator()(int) {}}; struct test4 { std::string operator()(int) const { return std::string(); }}; struct test5 { std::string operator()(int, std::string const& =std::string()) const { return std::string(); }}; struct test6 { template<typename T> std::string operator()(T) const { return std::string(); }}; struct test7 { template<typename T> T operator()(T) const { return T(); }}; struct test11 { int func(double, std::string) { return 0; }}; struct test12 { void func(double, std::string) {}}; struct test13 { void func(int) {}}; struct test14 { std::string func(int) const { return std::string(); }}; struct test15 { std::string func(int, std::string const& =std::string()) const { return std::string(); }}; struct test16 { template<typename T> std::string func(T) const { return std::string(); }}; struct test17 { template<typename T> T func(T) const { return T(); }}; }}
BOOST_TEST((local::can_call_funop<callable::test1, int (double, std::string)>::value == true)); BOOST_TEST((local::can_call_funop<callable::test1, double (int, std::string)>::value == true)); BOOST_TEST((local::can_call_funop<callable::test1, void (double, std::string)>::value == true)); BOOST_TEST((local::can_call_funop<callable::test1, void (int, std::string)>::value == true)); BOOST_TEST((local::can_call_funop<callable::test1, void (int, char const*)>::value == true)); BOOST_TEST((local::can_call_funop<callable::test1, int (double, int)>::value == false)); BOOST_TEST((local::can_call_funop<callable::test1, int (double)>::value == false)); BOOST_TEST((local::can_call_funop<callable::test2, int (double, std::string)>::value == false)); BOOST_TEST((local::can_call_funop<callable::test2, void (double, std::string)>::value == true)); BOOST_TEST((local::can_call_funop<callable::test2, void ( int, std::string)>::value == true)); BOOST_TEST((local::can_call_funop<callable::test2, void ( int, char const*)>::value == true));
BOOST_TEST((local::can_call_func<callable::test11, int (double, std::string)>::value == true)); BOOST_TEST((local::can_call_func<callable::test11, double (int, std::string)>::value == true)); BOOST_TEST((local::can_call_func<callable::test11, void (double, std::string)>::value == true)); BOOST_TEST((local::can_call_func<callable::test11, void (int, std::string)>::value == true)); BOOST_TEST((local::can_call_func<callable::test11, void (int, char const*)>::value == true)); BOOST_TEST((local::can_call_func<callable::test11, int (double, int)>::value == false)); BOOST_TEST((local::can_call_func<callable::test11, int (double)>::value == false)); BOOST_TEST((local::can_call_func<callable::test12, int (double, std::string)>::value == false)); BOOST_TEST((local::can_call_func<callable::test12, void (double, std::string)>::value == true)); BOOST_TEST((local::can_call_func<callable::test12, void ( int, std::string)>::value == true)); BOOST_TEST((local::can_call_func<callable::test12, void ( int, char const*)>::value == true));
As it can be seen from the example the traits check for the existence of a callable member function but not necessarily of the specified signature. Please check the Boost.TTI library for the latter.