Как специализировать шаблонную функцию для различения guish аргументов недействительных и недействительных функций - PullRequest
1 голос
/ 02 апреля 2020

Я бы хотел иметь 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...>> вызывает ошибку замещения.

1 Ответ

3 голосов
/ 02 апреля 2020

Проблема в том, что ваши черты плохо сформированы, когда C не может быть вызван с Args..., вам нужно СФИНАИРОВАТЬ вашу переменную:

template <typename R, typename C, typename TupleArgs, typename Enabler = void>
constexpr bool is_exact_invocable_r_v_impl = false;

template <typename R, typename C, typename... Args>
constexpr bool is_exact_invocable_r_v_impl<R,
                                          C,
                                          std::tuple<Args...>,
                                          std::void_t<std::invoke_result_t<C, Args...>>> =
    std::is_same_v<R, std::invoke_result_t<C, Args...>>;

template <typename R, typename C, typename... Args>
constexpr bool is_exact_invocable_r_v =
    is_exact_invocable_r_v_impl<R, C, std::tuple<Args...>>;

Демо

...