Я бы хотел иметь 2 функции: принимать void(*)(int)
и int(*)(int)
. Как написать type_trait, похожий на std :: is_invocable_r, но с проверкой точного возвращаемого типа (потому что любая функция может быть приведена к функции, возвращающей void).
#include <functional>
#include <type_traits>
#include <cstdio>
template <typename R, typename C, typename... Args>
constexpr bool is_exact_invocable_r_v =
std::is_same_v<R, std::invoke_result_t<C, Args...>>;
// std::is_invocable_r_v<R, C, Args...>;
template<typename C, std::enable_if_t<is_exact_invocable_r_v<int, C>, int> = 0>
void print(C)
{
printf("1\n");
}
template<typename C, std::enable_if_t<is_exact_invocable_r_v<int, C, int>, int> = 0>
void print(C)
{
printf("2\n");
}
template<typename C, std::enable_if_t<is_exact_invocable_r_v<void, C, int>, int> = 0>
void print(C)
{
printf("3\n");
}
int main()
{
print([](){return 0;});
print([](int){return 0;});
print([](int){});
}
std::is_invocable_r_v<R, C, Args...>
вызывает неоднозначность, потому что любой тип может быть приведен к void .
std::is_same_v<R, std::invoke_result_t<C, Args...>>
вызывает ошибку замещения.