Merge pull request #135 from ros2/function-traits-cleanup

Clean up function_traits
This commit is contained in:
Esteve Fernandez 2015-10-23 16:42:50 -07:00
commit f50d8c4525
4 changed files with 101 additions and 70 deletions

View file

@ -56,10 +56,9 @@ public:
template< template<
typename CallbackT, typename CallbackT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types< rclcpp::same_arguments<
CallbackT, CallbackT,
std::shared_ptr<typename ServiceT::Request>, SharedPtrCallback
std::shared_ptr<typename ServiceT::Response>
>::value >::value
>::type * = nullptr >::type * = nullptr
> >
@ -71,11 +70,9 @@ public:
template< template<
typename CallbackT, typename CallbackT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types< rclcpp::same_arguments<
CallbackT, CallbackT,
std::shared_ptr<rmw_request_id_t>, SharedPtrWithRequestHeaderCallback
std::shared_ptr<typename ServiceT::Request>,
std::shared_ptr<typename ServiceT::Response>
>::value >::value
>::type * = nullptr >::type * = nullptr
> >

View file

@ -61,9 +61,9 @@ public:
template< template<
typename CallbackT, typename CallbackT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types< rclcpp::same_arguments<
CallbackT, CallbackT,
typename std::shared_ptr<MessageT> SharedPtrCallback
>::value >::value
>::type * = nullptr >::type * = nullptr
> >
@ -75,10 +75,9 @@ public:
template< template<
typename CallbackT, typename CallbackT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types< rclcpp::same_arguments<
CallbackT, CallbackT,
typename std::shared_ptr<MessageT>, SharedPtrWithInfoCallback
const rmw_message_info_t &
>::value >::value
>::type * = nullptr >::type * = nullptr
> >
@ -90,9 +89,9 @@ public:
template< template<
typename CallbackT, typename CallbackT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types< rclcpp::same_arguments<
CallbackT, CallbackT,
typename std::shared_ptr<const MessageT> ConstSharedPtrCallback
>::value >::value
>::type * = nullptr >::type * = nullptr
> >
@ -104,10 +103,9 @@ public:
template< template<
typename CallbackT, typename CallbackT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types< rclcpp::same_arguments<
CallbackT, CallbackT,
typename std::shared_ptr<const MessageT>, ConstSharedPtrWithInfoCallback
const rmw_message_info_t &
>::value >::value
>::type * = nullptr >::type * = nullptr
> >
@ -119,9 +117,9 @@ public:
template< template<
typename CallbackT, typename CallbackT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types< rclcpp::same_arguments<
CallbackT, CallbackT,
typename std::unique_ptr<MessageT> UniquePtrCallback
>::value >::value
>::type * = nullptr >::type * = nullptr
> >
@ -133,10 +131,9 @@ public:
template< template<
typename CallbackT, typename CallbackT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types< rclcpp::same_arguments<
CallbackT, CallbackT,
typename std::unique_ptr<MessageT>, UniquePtrWithInfoCallback
const rmw_message_info_t &
>::value >::value
>::type * = nullptr >::type * = nullptr
> >

View file

@ -28,32 +28,47 @@ namespace rclcpp
* See http://blogs.msdn.com/b/vcblog/archive/2015/06/19/c-11-14-17-features-in-vs-2015-rtm.aspx * See http://blogs.msdn.com/b/vcblog/archive/2015/06/19/c-11-14-17-features-in-vs-2015-rtm.aspx
*/ */
// Remove the first item in a tuple
template<typename T>
struct tuple_tail;
template<typename Head, typename ... Tail>
struct tuple_tail<std::tuple<Head, Tail ...>>
{
using type = std::tuple<Tail ...>;
};
// std::function
template<typename FunctionT> template<typename FunctionT>
struct function_traits struct function_traits
{ {
static constexpr std::size_t arity = using arguments = typename tuple_tail<
function_traits<decltype( & FunctionT::operator())>::arity - 1; typename function_traits<decltype( & FunctionT::operator())>::arguments>::type;
static constexpr std::size_t arity = std::tuple_size<arguments>::value;
template<std::size_t N> template<std::size_t N>
using argument_type = using argument_type = typename std::tuple_element<N, arguments>::type;
typename function_traits<decltype( & FunctionT::operator())>::template argument_type<N + 1>;
}; };
// Free functions
template<typename ReturnTypeT, typename ... Args> template<typename ReturnTypeT, typename ... Args>
struct function_traits<ReturnTypeT(Args ...)> struct function_traits<ReturnTypeT(Args ...)>
{ {
static constexpr std::size_t arity = sizeof ... (Args); using arguments = std::tuple<Args ...>;
static constexpr std::size_t arity = std::tuple_size<arguments>::value;
template<std::size_t N> template<std::size_t N>
using argument_type = typename std::tuple_element<N, std::tuple<Args ...>>::type; using argument_type = typename std::tuple_element<N, arguments>::type;
}; };
// Function pointers
template<typename ReturnTypeT, typename ... Args> template<typename ReturnTypeT, typename ... Args>
struct function_traits<ReturnTypeT (*)(Args ...)>: public function_traits<ReturnTypeT(Args ...)> struct function_traits<ReturnTypeT (*)(Args ...)>: public function_traits<ReturnTypeT(Args ...)>
{}; {};
// Lambdas
template<typename ClassT, typename ReturnTypeT, typename ... Args> template<typename ClassT, typename ReturnTypeT, typename ... Args>
struct function_traits<ReturnTypeT (ClassT::*)(Args ...) const> struct function_traits<ReturnTypeT (ClassT::*)(Args ...) const>
: public function_traits<ReturnTypeT(ClassT &, Args ...)> : public function_traits<ReturnTypeT(ClassT &, Args ...)>
@ -67,34 +82,19 @@ template<std::size_t Arity, typename FunctorT>
struct arity_comparator : std::integral_constant< struct arity_comparator : std::integral_constant<
bool, (Arity == function_traits<FunctorT>::arity)>{}; bool, (Arity == function_traits<FunctorT>::arity)>{};
template<typename FunctorT, typename First, typename ... Last> template<typename FunctorT, typename ... Args>
struct check_argument_types_recursive : std::conditional< struct check_arguments : std::is_same<
std::is_same< typename function_traits<FunctorT>::arguments,
typename function_traits<FunctorT>::template argument_type< std::tuple<Args ...>
function_traits<FunctorT>::arity - sizeof ... (Last) -1
>,
First
>::value,
check_argument_types_recursive<FunctorT, Last ...>,
std::false_type>::type
{};
template<typename FunctorT, typename Arg>
struct check_argument_types_recursive<FunctorT, Arg>: std::is_same<
typename function_traits<FunctorT>::template argument_type<
function_traits<FunctorT>::arity - 1
>,
Arg
> >
{}; {};
template<typename FunctorT, typename ... Args> template<typename FunctorAT, typename FunctorBT>
struct check_argument_types : std::conditional< struct same_arguments : std::is_same<
arity_comparator<sizeof ... (Args), FunctorT>::value, typename function_traits<FunctorAT>::arguments,
check_argument_types_recursive<FunctorT, Args ...>, typename function_traits<FunctorBT>::arguments
std::false_type>::type >
{}; {};
} /* namespace rclcpp */ } /* namespace rclcpp */
#endif /* RCLCPP_RCLCPP_FUNCTION_TRAITS_HPP_ */ #endif /* RCLCPP_RCLCPP_FUNCTION_TRAITS_HPP_ */

View file

@ -81,7 +81,7 @@ int func_accept_callback(FunctorT callback)
template< template<
typename FunctorT, typename FunctorT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types<FunctorT, int>::value rclcpp::check_arguments<FunctorT, int>::value
>::type * = nullptr >::type * = nullptr
> >
int func_accept_callback(FunctorT callback) int func_accept_callback(FunctorT callback)
@ -93,7 +93,7 @@ int func_accept_callback(FunctorT callback)
template< template<
typename FunctorT, typename FunctorT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types<FunctorT, int, int>::value rclcpp::check_arguments<FunctorT, int, int>::value
>::type * = nullptr >::type * = nullptr
> >
int func_accept_callback(FunctorT callback) int func_accept_callback(FunctorT callback)
@ -106,7 +106,7 @@ int func_accept_callback(FunctorT callback)
template< template<
typename FunctorT, typename FunctorT,
typename std::enable_if< typename std::enable_if<
rclcpp::check_argument_types<FunctorT, int, char>::value rclcpp::check_arguments<FunctorT, int, char>::value
>::type * = nullptr >::type * = nullptr
> >
int func_accept_callback(FunctorT callback) int func_accept_callback(FunctorT callback)
@ -301,38 +301,38 @@ TEST(TestFunctionTraits, argument_types) {
/* /*
Tests that funcion_traits checks the types of the arguments of several functors. Tests that funcion_traits checks the types of the arguments of several functors.
*/ */
TEST(TestFunctionTraits, check_argument_types) { TEST(TestFunctionTraits, check_arguments) {
// Test regular functions // Test regular functions
static_assert( static_assert(
rclcpp::check_argument_types<decltype(func_one_int), int>::value, rclcpp::check_arguments<decltype(func_one_int), int>::value,
"Functor accepts a single int as arguments"); "Functor accepts a single int as arguments");
static_assert( static_assert(
!rclcpp::check_argument_types<decltype(func_one_int), char>::value, !rclcpp::check_arguments<decltype(func_one_int), char>::value,
"Functor does not accept a char as argument"); "Functor does not accept a char as argument");
static_assert( static_assert(
!rclcpp::check_argument_types<decltype(func_one_int), char, int>::value, !rclcpp::check_arguments<decltype(func_one_int), char, int>::value,
"Functor does not accept two arguments"); "Functor does not accept two arguments");
static_assert( static_assert(
!rclcpp::check_argument_types<decltype(func_two_ints), int>::value, !rclcpp::check_arguments<decltype(func_two_ints), int>::value,
"Functor does not accept a single int as argument, requires two ints"); "Functor does not accept a single int as argument, requires two ints");
static_assert( static_assert(
rclcpp::check_argument_types<decltype(func_two_ints), int, int>::value, rclcpp::check_arguments<decltype(func_two_ints), int, int>::value,
"Functor accepts two ints as arguments"); "Functor accepts two ints as arguments");
static_assert( static_assert(
!rclcpp::check_argument_types<decltype(func_two_ints), bool, int>::value, !rclcpp::check_arguments<decltype(func_two_ints), bool, int>::value,
"Functor does not accept a bool and an int as arguments, requires two ints"); "Functor does not accept a bool and an int as arguments, requires two ints");
static_assert( static_assert(
!rclcpp::check_argument_types<decltype(func_two_ints), int, char>::value, !rclcpp::check_arguments<decltype(func_two_ints), int, char>::value,
"Functor does not accept an int and a char as arguments, requires two ints"); "Functor does not accept an int and a char as arguments, requires two ints");
static_assert( static_assert(
rclcpp::check_argument_types<decltype(func_one_int_one_char), int, char>::value, rclcpp::check_arguments<decltype(func_one_int_one_char), int, char>::value,
"Functor accepts an int and a char as arguments"); "Functor accepts an int and a char as arguments");
// Test lambdas // Test lambdas
@ -349,31 +349,68 @@ TEST(TestFunctionTraits, check_argument_types) {
}; };
static_assert( static_assert(
rclcpp::check_argument_types<decltype(lambda_one_int), int>::value, rclcpp::check_arguments<decltype(lambda_one_int), int>::value,
"Functor accepts an int as the only argument"); "Functor accepts an int as the only argument");
static_assert( static_assert(
rclcpp::check_argument_types<decltype(lambda_two_ints), int, int>::value, rclcpp::check_arguments<decltype(lambda_two_ints), int, int>::value,
"Functor accepts two ints as arguments"); "Functor accepts two ints as arguments");
static_assert( static_assert(
rclcpp::check_argument_types<decltype(lambda_one_int_one_char), int, char>::value, rclcpp::check_arguments<decltype(lambda_one_int_one_char), int, char>::value,
"Functor accepts an int and a char as arguments"); "Functor accepts an int and a char as arguments");
// Test objects that have a call operator // Test objects that have a call operator
static_assert( static_assert(
rclcpp::check_argument_types<FunctionObjectOneInt, int>::value, rclcpp::check_arguments<FunctionObjectOneInt, int>::value,
"Functor accepts an int as the only argument"); "Functor accepts an int as the only argument");
static_assert( static_assert(
rclcpp::check_argument_types<FunctionObjectTwoInts, int, int>::value, rclcpp::check_arguments<FunctionObjectTwoInts, int, int>::value,
"Functor accepts two ints as arguments"); "Functor accepts two ints as arguments");
static_assert( static_assert(
rclcpp::check_argument_types<FunctionObjectOneIntOneChar, int, char>::value, rclcpp::check_arguments<FunctionObjectOneIntOneChar, int, char>::value,
"Functor accepts an int and a char as arguments"); "Functor accepts an int and a char as arguments");
} }
/*
Tests that same_arguments work.
*/
TEST(TestFunctionTraits, same_arguments) {
auto lambda_one_int = [](int) {
return 1;
};
auto lambda_two_ints = [](int, int) {
return 1;
};
static_assert(
rclcpp::same_arguments<decltype(lambda_one_int), decltype(func_one_int)>::value,
"Lambda and function have the same arguments");
static_assert(
!rclcpp::same_arguments<decltype(lambda_two_ints), decltype(func_one_int)>::value,
"Lambda and function have different arguments");
static_assert(
!rclcpp::same_arguments<decltype(func_one_int_one_char), decltype(func_two_ints)>::value,
"Functions have different arguments");
static_assert(
!rclcpp::same_arguments<decltype(lambda_one_int), decltype(lambda_two_ints)>::value,
"Lambdas have different arguments");
static_assert(
rclcpp::same_arguments<FunctionObjectTwoInts, decltype(func_two_ints)>::value,
"Functor and function have the same arguments");
static_assert(
rclcpp::same_arguments<FunctionObjectTwoInts, decltype(lambda_two_ints)>::value,
"Functor and lambda have the same arguments");
}
/* /*
Tests that functions are matched via SFINAE. Tests that functions are matched via SFINAE.
*/ */