Как указывает NathanOliver в комментарии , вы не можете сделать это для обычного функционального объекта.Поэтому мы сосредоточимся только на лямбде.
Во-первых, мы можем создать вспомогательный класс, который проверяет, можно ли вызывать F
с аргументами, выбранными из Args...
через последовательность индексов Index_sequence
:
template <typename F, typename Index_sequence, typename... Args>
struct is_invocable_for_indices : std::false_type {};
template <typename F, size_t... Is, typename... Args>
struct is_invocable_for_indices<F, std::index_sequence<Is...>, Args...>
: std::is_invocable<F, std::tuple_element_t<Is, std::tuple<Args...>>...> {};
template <typename F, typename Index_sequence, typename... Args>
inline constexpr bool is_invocable_for_indices_v = is_invocable_for_indices<F, Index_sequence, Args...>::value;
// example use
auto f = [](int i = 0) {};
auto g = [](int i) {};
static_assert(is_invocable_for_indices_v<decltype(f), std::index_sequence<>, int>);
static_assert(!is_invocable_for_indices_v<decltype(g), std::index_sequence<>, int>);
static_assert(is_invocable_for_indices_v<decltype(g), std::index_sequence<0>, int>);
Пусть Args
будут типами параметров F
, которые могут быть обнаружены с помощью decltype(&F::operator())
(идея приходит из этого ответа ).Теперь вы можете проверить, имеет ли F
аргумент по умолчанию, проверив, можно ли вызвать F
с первыми sizeof...(Args) - 1
аргументами Args
.Таким образом, мы можем определить has_defulat_arg
следующим образом:
template <typename F, typename OperatorType>
struct has_defulat_arg_impl : std::false_type {};
template <typename F, typename R, typename... Args>
struct has_defulat_arg_impl<F, R(F::*)(Args...) const>
: is_invocable_for_indices<F, std::make_index_sequence<sizeof...(Args) - 1>, Args...> {};
// specialization for the case where sizeof...(Args) == 0
template <typename F, typename R>
struct has_defulat_arg_impl<F, R(F::*)() const> : std::false_type {};
template <typename F>
using has_defulat_arg = has_defulat_arg_impl<F, decltype(&F::operator())>;
template <typename F>
inline constexpr bool has_defulat_arg_v = has_defulat_arg<F>::value;
// example use
auto f = [](int i = 0) {};
auto g = [](int i) {};
static_assert(has_defulat_arg_v<decltype(f)>);
static_assert(!has_defulat_arg_v<decltype(g)>);
LIVE EXAMPLE