Как выводить шаблонный аргумент после вариационных аргументов?

У меня есть следующая функция шаблона:

template <typename...Args, typename Func>
void call(const char *name, Args...args, Func f)
{
f(3);
}

Когда я пытаюсь использовать его, как

    call("test", 1, 2, 3, [=](int i) { std::cout<< i; });

Компилятор жалуется, что не может вывести аргумент шаблона Func,
Как решить эту проблему, зная, что args может быть любого типа, кроме указателя на функцию.

3

Решение

Написать get_last, который извлекает последний элемент пакета параметров.

Назови это f, Вызов f,

В качестве примера,

template<typename T0>
auto get_last( T0&& t0 )->decltype(std::forward<T0>(t0))
{
return std::forward<T0>(t0);
}
template<typename T0, typename... Ts>
auto get_last( T0&& t0, Ts&&... ts )->decltype(get_last(std::forward<Ts>(ts)...))
{
return get_last(std::forward<Ts>(ts)...);
}

если вас не волнует разрешение перегрузки, просто позвоните get_last и рассматривать его как функтор может быть достаточно:

template <typename...Args>
void call(const char *name, Args...&& args)
{
auto&& f = get_last(std::forward<Args>(args)...);
f(3);
}

Следующим шагом будет сделать SFINAE enable_if магия, чтобы сделать call не соответствует, если вы не передали действительный функтор в последнюю очередь: однако, это, вероятно, излишним.

Чтобы обнаружить, если f(3) будет работать, простой черт класс:

// trivial traits class:
template<typename T>
struct is_type:std::true_type {};

template<typename Functor, typename=void>
struct can_be_called_with_3:std::false_type {}

template<typename Functor>
struct can_be_called_with_3<Functor,
typename std::enable_if<
std::is_type< decltype(
std::declval<Functor>(3)
) >::value
>::type
>:std::true_type {}

что довольно глупо Класс «черт характера» должен быть использован, если ваши требования к переданному типу являются более сложными (скажем, вы хотите, чтобы он вызывался с аргументами).

Тогда вы увеличиваете call с:

template <typename...Args>
auto call(const char *name, Args...&& args)
-> typename std::enable_if<
can_be_called_with_3< decltype( get_last(std::forward<Args>(args)... ) ) >::value
>::type
{ /* body unchanged */ }

что довольно тупо

4

Другие решения

От 14.1п11:

Пакет параметров шаблона шаблона функции не должен соблюдаться
другим параметром шаблона, если этот параметр шаблона не может быть выведен из списка параметров типа
шаблона функции или имеет аргумент по умолчанию (14.8.2).

Если вы хотите оставить вызываемый объект последним аргументом, вы можете использовать forward_as_tuple:

template <typename...Args, typename Func>
void call(const char *name, std::tuple<Args...> args, Func f)
{
f(3);
}

call("test", std::forward_as_tuple(1, 2, 3), [=](int i) { std::cout<< i; });

Мы можем на самом деле сделать лучше, синтезируя tuple также содержать вызываемое:

#include <tuple>

template<typename... Args_F>
void call_impl(const char *name, std::tuple<Args_F... &&> args_f) {
auto &&f = std::get<sizeof...(Args_F) - 1>(args_f);
f(3);
}

template<typename...ArgsF>
void call(const char *name, ArgsF &&...args_f) {
call_impl(name, std::tuple<ArgsF &&...>(std::forward<ArgsF>(args_f)...));
}
8

если вы хотите добавить пакет аргументов в качестве шаблона, вы не можете написать это так, как вы это уже делали:

template <typename...Args, typename Func>
void call(const char *name, Args...args, Func f)
{
f(3);
}

Но вы можете упаковать их в std::tuple:

template <typename...Args, typename Func>
void call(const char *name, std::tuple<Args...> args, Func f)
{
f(3);
}

call("test", std::forward_as_tuple(1, 2, 3), [=](int i) { std::cout<< i; });
0
По вопросам рекламы [email protected]