Added tests for rclcpp::function_traits and work around expression SFINAE
This commit is contained in:
parent
5795861009
commit
9f65b9dd59
5 changed files with 390 additions and 59 deletions
|
@ -22,6 +22,7 @@ if(AMENT_ENABLE_TESTING)
|
|||
|
||||
include_directories(include)
|
||||
|
||||
ament_add_gtest(test_function_traits test/test_function_traits.cpp)
|
||||
ament_add_gtest(test_mapped_ring_buffer test/test_mapped_ring_buffer.cpp)
|
||||
ament_add_gtest(test_intra_process_manager test/test_intra_process_manager.cpp)
|
||||
if(TARGET test_intra_process_manager)
|
||||
|
|
|
@ -57,34 +57,42 @@ struct AnySubscriptionCallback
|
|||
|
||||
AnySubscriptionCallback(const AnySubscriptionCallback &) = default;
|
||||
|
||||
template<typename CallbackT,
|
||||
typename std::enable_if<
|
||||
function_traits<CallbackT>::arity == 1
|
||||
>::type * = nullptr,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
typename function_traits<CallbackT>::template argument_type<0>,
|
||||
typename std::shared_ptr<MessageT>
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
template<
|
||||
typename CallbackT,
|
||||
std::size_t Arity = 1
|
||||
>
|
||||
void set(CallbackT callback)
|
||||
typename std::enable_if<rclcpp::arity_comparator<Arity, CallbackT>::value, void>::type
|
||||
set(
|
||||
CallbackT callback,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
typename function_traits<CallbackT>::template argument_type<0>,
|
||||
typename std::shared_ptr<MessageT>
|
||||
>::value
|
||||
>::type * = nullptr)
|
||||
{
|
||||
shared_ptr_callback = callback;
|
||||
}
|
||||
|
||||
template<typename CallbackT,
|
||||
typename std::enable_if<
|
||||
function_traits<CallbackT>::arity == 2
|
||||
>::type * = nullptr,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
typename function_traits<CallbackT>::template argument_type<0>,
|
||||
typename std::shared_ptr<MessageT>
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
template<
|
||||
typename CallbackT,
|
||||
std::size_t Arity = 2
|
||||
>
|
||||
void set(CallbackT callback)
|
||||
typename std::enable_if<rclcpp::arity_comparator<Arity, CallbackT>::value, void>::type
|
||||
set(
|
||||
CallbackT callback,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
typename function_traits<CallbackT>::template argument_type<0>,
|
||||
typename std::shared_ptr<MessageT>
|
||||
>::value
|
||||
>::type * = nullptr,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
typename function_traits<CallbackT>::template argument_type<1>,
|
||||
rmw_message_info_t
|
||||
>::value
|
||||
>::type * = nullptr)
|
||||
{
|
||||
static_assert(std::is_same<
|
||||
typename function_traits<CallbackT>::template argument_type<1>,
|
||||
|
|
|
@ -58,6 +58,12 @@ struct function_traits<ReturnTypeT (ClassT::*)(Args ...) const>
|
|||
: public function_traits<ReturnTypeT(ClassT &, Args ...)>
|
||||
{};
|
||||
|
||||
template<std::size_t Arity, typename FunctorT>
|
||||
struct arity_comparator
|
||||
{
|
||||
static constexpr bool value = (Arity == function_traits<FunctorT>::arity);
|
||||
};
|
||||
|
||||
} /* namespace rclcpp */
|
||||
|
||||
#endif /* RCLCPP_RCLCPP_FUNCTION_TRAITS_HPP_ */
|
||||
|
|
|
@ -250,9 +250,17 @@ private:
|
|||
template<
|
||||
typename ServiceT,
|
||||
typename FunctorT,
|
||||
typename std::enable_if<
|
||||
function_traits<FunctorT>::arity == 2
|
||||
>::type * = nullptr,
|
||||
std::size_t Arity = 2
|
||||
>
|
||||
typename std::enable_if<
|
||||
rclcpp::arity_comparator<Arity, FunctorT>::value,
|
||||
typename rclcpp::service::Service<ServiceT>::SharedPtr
|
||||
>::type
|
||||
create_service_internal(
|
||||
std::shared_ptr<rmw_node_t> node_handle,
|
||||
rmw_service_t * service_handle,
|
||||
const std::string & service_name,
|
||||
FunctorT callback,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
typename function_traits<FunctorT>::template argument_type<0>,
|
||||
|
@ -264,14 +272,7 @@ private:
|
|||
typename function_traits<FunctorT>::template argument_type<1>,
|
||||
typename std::shared_ptr<typename ServiceT::Response>
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
>
|
||||
typename rclcpp::service::Service<ServiceT>::SharedPtr
|
||||
create_service_internal(
|
||||
std::shared_ptr<rmw_node_t> node_handle,
|
||||
rmw_service_t * service_handle,
|
||||
const std::string & service_name,
|
||||
FunctorT callback)
|
||||
>::type * = nullptr)
|
||||
{
|
||||
typename rclcpp::service::Service<ServiceT>::CallbackType callback_without_header =
|
||||
callback;
|
||||
|
@ -282,9 +283,17 @@ private:
|
|||
template<
|
||||
typename ServiceT,
|
||||
typename FunctorT,
|
||||
typename std::enable_if<
|
||||
function_traits<FunctorT>::arity == 3
|
||||
>::type * = nullptr,
|
||||
std::size_t Arity = 3
|
||||
>
|
||||
typename std::enable_if<
|
||||
arity_comparator<Arity, FunctorT>::value,
|
||||
typename rclcpp::service::Service<ServiceT>::SharedPtr
|
||||
>::type
|
||||
create_service_internal(
|
||||
std::shared_ptr<rmw_node_t> node_handle,
|
||||
rmw_service_t * service_handle,
|
||||
const std::string & service_name,
|
||||
FunctorT callback,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
typename function_traits<FunctorT>::template argument_type<0>,
|
||||
|
@ -296,35 +305,14 @@ private:
|
|||
typename function_traits<FunctorT>::template argument_type<1>,
|
||||
typename std::shared_ptr<typename ServiceT::Request>
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
/*
|
||||
TODO(esteve): reenable this block of code when VS2015 gets better support
|
||||
for SFINAE and remove the static_assert from the body of this method. For
|
||||
more info about the current support for SFINAE in VS2015 RC:
|
||||
|
||||
http://blogs.msdn.com/b/vcblog/archive/2015/04/29/c-11-14-17-features-in-vs-2015-rc.aspx
|
||||
,
|
||||
>::type * = nullptr,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
typename function_traits<FunctorT>::template argument_type<2>,
|
||||
typename std::shared_ptr<typename ServiceT::Response>
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
*/
|
||||
>
|
||||
typename rclcpp::service::Service<ServiceT>::SharedPtr
|
||||
create_service_internal(
|
||||
std::shared_ptr<rmw_node_t> node_handle,
|
||||
rmw_service_t * service_handle,
|
||||
const std::string & service_name,
|
||||
FunctorT callback)
|
||||
>::type * = nullptr)
|
||||
{
|
||||
static_assert(
|
||||
std::is_same<
|
||||
typename function_traits<FunctorT>::template argument_type<2>,
|
||||
typename std::shared_ptr<typename ServiceT::Response>
|
||||
>::value, "Third argument must be of type std::shared_ptr<ServiceT::Response>");
|
||||
|
||||
typename rclcpp::service::Service<ServiceT>::CallbackWithHeaderType callback_with_header =
|
||||
callback;
|
||||
return service::Service<ServiceT>::make_shared(
|
||||
|
|
328
rclcpp/test/test_function_traits.cpp
Normal file
328
rclcpp/test/test_function_traits.cpp
Normal file
|
@ -0,0 +1,328 @@
|
|||
// Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rclcpp/function_traits.hpp>
|
||||
|
||||
int func_no_args()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int func_one_int(int)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int func_two_ints(int, int)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
int func_one_int_one_char(int, char)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
struct FunctionObjectNoArgs
|
||||
{
|
||||
int operator()() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionObjectOneInt
|
||||
{
|
||||
int operator()(int) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionObjectTwoInts
|
||||
{
|
||||
int operator()(int, int) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionObjectOneIntOneChar
|
||||
{
|
||||
int operator()(int, char) const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename FunctorT,
|
||||
std::size_t Arity = 1
|
||||
>
|
||||
typename std::enable_if<rclcpp::arity_comparator<Arity, FunctorT>::value, int>::type
|
||||
func_accept_callback(FunctorT callback,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
int,
|
||||
typename rclcpp::function_traits<FunctorT>::template argument_type<0>
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
)
|
||||
{
|
||||
int a = 4;
|
||||
return callback(a);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FunctorT,
|
||||
std::size_t Arity = 2
|
||||
>
|
||||
typename std::enable_if<rclcpp::arity_comparator<Arity, FunctorT>::value, int>::type
|
||||
func_accept_callback(FunctorT callback,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
int,
|
||||
typename rclcpp::function_traits<FunctorT>::template argument_type<0>
|
||||
>::value
|
||||
>::type * = nullptr,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
int,
|
||||
typename rclcpp::function_traits<FunctorT>::template argument_type<1>
|
||||
>::value
|
||||
>::type * = nullptr)
|
||||
{
|
||||
int a = 5;
|
||||
int b = 6;
|
||||
return callback(a, b);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FunctorT,
|
||||
std::size_t Arity = 2
|
||||
>
|
||||
typename std::enable_if<rclcpp::arity_comparator<Arity, FunctorT>::value, int>::type
|
||||
func_accept_callback(FunctorT callback,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
int,
|
||||
typename rclcpp::function_traits<FunctorT>::template argument_type<0>
|
||||
>::value
|
||||
>::type * = nullptr,
|
||||
typename std::enable_if<
|
||||
std::is_same<
|
||||
char,
|
||||
typename rclcpp::function_traits<FunctorT>::template argument_type<1>
|
||||
>::value
|
||||
>::type * = nullptr)
|
||||
{
|
||||
int a = 7;
|
||||
char b = 8;
|
||||
return callback(a, b);
|
||||
}
|
||||
|
||||
/*
|
||||
Tests that funcion_traits calculates arity of several functors.
|
||||
*/
|
||||
TEST(TestFunctionTraits, arity) {
|
||||
// Test regular functions
|
||||
static_assert(
|
||||
rclcpp::function_traits<decltype(func_no_args)>::arity == 0,
|
||||
"Functor does not accept arguments");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<decltype(func_one_int)>::arity == 1,
|
||||
"Functor only accepts one argument");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<decltype(func_two_ints)>::arity == 2,
|
||||
"Functor only accepts two arguments");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<decltype(func_one_int_one_char)>::arity == 2,
|
||||
"Functor only accepts two arguments");
|
||||
|
||||
// Test lambdas
|
||||
auto lambda_no_args = []() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto lambda_one_int = [](int) {
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto lambda_two_ints = [](int, int) {
|
||||
return 2;
|
||||
};
|
||||
|
||||
auto lambda_one_int_one_char = [](int, char) {
|
||||
return 3;
|
||||
};
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<decltype(lambda_no_args)>::arity == 0,
|
||||
"Functor does not accept arguments");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<decltype(lambda_one_int)>::arity == 1,
|
||||
"Functor only accepts one argument");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<decltype(lambda_two_ints)>::arity == 2,
|
||||
"Functor only accepts two arguments");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<decltype(lambda_one_int_one_char)>::arity == 2,
|
||||
"Functor only accepts two arguments");
|
||||
|
||||
// Test objects that have a call operator
|
||||
static_assert(
|
||||
rclcpp::function_traits<FunctionObjectNoArgs>::arity == 0,
|
||||
"Functor does not accept arguments");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<FunctionObjectOneInt>::arity == 1,
|
||||
"Functor only accepts one argument");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<FunctionObjectTwoInts>::arity == 2,
|
||||
"Functor only accepts two arguments");
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits<FunctionObjectOneIntOneChar>::arity == 2,
|
||||
"Functor only accepts two arguments");
|
||||
}
|
||||
|
||||
/*
|
||||
Tests that funcion_traits deducts the type of the arguments of several functors.
|
||||
*/
|
||||
TEST(TestFunctionTraits, argument_types) {
|
||||
// Test regular functions
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<decltype(func_one_int)>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<decltype(func_two_ints)>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<decltype(func_two_ints)>::template argument_type<1>
|
||||
>::value, "Functor accepts an int as second argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<decltype(func_one_int_one_char)>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
char,
|
||||
rclcpp::function_traits<decltype(func_one_int_one_char)>::template argument_type<1>
|
||||
>::value, "Functor accepts a char as second argument");
|
||||
|
||||
// Test lambdas
|
||||
auto lambda_one_int = [](int) {
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto lambda_two_ints = [](int, int) {
|
||||
return 2;
|
||||
};
|
||||
|
||||
auto lambda_one_int_one_char = [](int, char) {
|
||||
return 3;
|
||||
};
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<decltype(lambda_one_int)>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<decltype(lambda_two_ints)>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<decltype(lambda_two_ints)>::template argument_type<1>
|
||||
>::value, "Functor accepts an int as second argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<decltype(lambda_one_int_one_char)>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
char,
|
||||
rclcpp::function_traits<decltype(lambda_one_int_one_char)>::template argument_type<1>
|
||||
>::value, "Functor accepts a char as second argument");
|
||||
|
||||
// Test objects that have a call operator
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<FunctionObjectOneInt>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<FunctionObjectTwoInts>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<FunctionObjectTwoInts>::template argument_type<1>
|
||||
>::value, "Functor accepts an int as second argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
int,
|
||||
rclcpp::function_traits<FunctionObjectOneIntOneChar>::template argument_type<0>
|
||||
>::value, "Functor accepts an int as first argument");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
char,
|
||||
rclcpp::function_traits<FunctionObjectOneIntOneChar>::template argument_type<1>
|
||||
>::value, "Functor accepts a char as second argument");
|
||||
}
|
||||
|
||||
/*
|
||||
Tests that functions are matched via SFINAE.
|
||||
*/
|
||||
TEST(TestFunctionTraits, sfinae_match) {
|
||||
EXPECT_EQ(1, func_accept_callback(func_one_int));
|
||||
|
||||
EXPECT_EQ(2, func_accept_callback(func_two_ints));
|
||||
|
||||
EXPECT_EQ(3, func_accept_callback(func_one_int_one_char));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue