Обычно не рекомендуется принимать std::function
по значению, если только вы не находитесь в режиме «двоичного разграничения» (например, динамическая библиотека, «непрозрачный» API), поскольку, как вы только что засвидетельствовали, они играют хаос с перегрузкой. Когда функция действительно принимает std::function
по значению, то вызывающему часто приходится создавать объект, чтобы избежать проблем с перегрузкой (если функция вообще перегружена).
Поскольку вы уже написали шаблон, вполне вероятно, что вы не используете std::function
(в качестве типа параметра) для преимуществ стирания типа. Если вы хотите проверить произвольные функторы, то для этого вам понадобятся некоторые особенности. Например. Boost.FunctionTypes имеет такие черты, как result_type
и parameter_types
. Минимальный, функциональный пример:
#include <functional>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/function_type.hpp>
template<typename Functor>
void test(Functor functor) // accept arbitrary functor!
{
namespace ft = boost::function_types;
typedef typename ft::result_type<Functor>::type result_type;
typedef ft::parameter_types<Functor> parameter_types;
typedef typename boost::mpl::push_front<
parameter_types
, result_type
>::type sequence_type;
// sequence_type is now a Boost.MPL sequence in the style of
// mpl::vector<int, double, long> if the signature of the
// analyzed functor were int(double, long)
// We now build a function type out of the MPL sequence
typedef typename ft::function_type<sequence_type>::type function_type;
std::function<function_type> function = std::move(functor);
}
В качестве последнего замечания, я не рекомендую интроспективные функторы (т. Е. Подталкивать к их типу результата и типу аргумента) в общем случае, поскольку они просто не работают для полиморфных функторов. Рассмотрим несколько перегруженных operator()
: тогда нет «канонического» типа результата или типа аргумента. В C ++ 11 лучше «охотно» принимать любой тип функтора или ограничивать их, используя такие методы, как SFINAE или static_assert
, в зависимости от потребностей, а затем (когда параметры доступны), чтобы использовать std::result_of
для проверки тип результата для заданного набора аргументов . Случай, когда желательно ограничить заранее, состоит в том, когда целью является сохранение функторов, например, в. контейнер std::function<Sig>
.
Чтобы понять, что я имею в виду под предыдущим абзацем, достаточно протестировать приведенный выше фрагмент с полиморфными функторами.