Возможно, не идеальное решение ... но вы можете попробовать с passepartout
struct passepartout
{
template <typename T>
operator T & ();
template <typename T>
operator T && ();
};
Обратите внимание, что операторы преобразования только объявлены, но не определены; поэтому эта структура может использоваться в decltype()
и std::declval()
(и std::is_invocable
), но не может быть реализована.
Теперь вы можете написать higherOrderFunc
проходную ссылку на passepartout
на std::is_invocable
.
template <typename F,
std::enable_if_t<
std::is_invocable_v<F, passepartout &>
&& ! std::is_invocable_v<F, passepartout &, passepartout &>, bool>
= true>
void higherOrderFunc (F)
{ std::cout << "-- one parameter callable" << std::endl; }
template <typename F,
std::enable_if_t<
std::is_invocable_v<F, passepartout &, passepartout &>, bool> = true>
void higherOrderFunc (F)
{ std::cout << "-- two parameter callable" << std::endl; }
Хитрость в том, что если вызываемый ожидает auto
(или auto &
, или auto &&
), тип выводится как passepartout
; когда вызываемое ожидание определенного типа (int
, с или без ссылок, в следующих примерах), шаблон operator T & ()
(или operator T && ()
, в зависимости от случаев) совместим (в некотором смысле) с ожидаемым типом.
Ниже приведен полный пример компиляции
#include <type_traits>
#include <iostream>
struct passepartout
{
template <typename T>
operator T & ();
template <typename T>
operator T && ();
};
template <typename F,
std::enable_if_t<
std::is_invocable_v<F, passepartout &>
&& ! std::is_invocable_v<F, passepartout &, passepartout &>, bool>
= true>
void higherOrderFunc (F)
{ std::cout << "-- one parameter callable" << std::endl; }
template <typename F,
std::enable_if_t<
std::is_invocable_v<F, passepartout &, passepartout &>, bool> = true>
void higherOrderFunc (F)
{ std::cout << "-- two parameter callable" << std::endl; }
int main ()
{
auto l1a = [](auto &&){};
auto l1b = [](int &){};
auto l2a = [](auto &, int &&){};
auto l2b = [](auto, int const &){};
auto l2c = [](auto &&, auto const &){};
auto l2d = [](int &&, auto const &, auto && ...){};
higherOrderFunc(l1a);
higherOrderFunc(l1b);
higherOrderFunc(l2a);
higherOrderFunc(l2b);
higherOrderFunc(l2c);
higherOrderFunc(l2c);
higherOrderFunc(l2d);
}