Как создать шаблон как с аргументом типа по умолчанию, так и с аргументом вариативного типа? или любой обходной путь

Я создал структуру типажей FnOnArg, чтобы узнать, может ли Fn вызвать Arg.

template<typename Fn, typename Arg, typename=void>
struct FnOnArg: std::false_type {};

template<typename Fn, typename Arg>
struct FnOnArg<Fn, Arg, std::void_t<decltype(std::declval<Fn>()(std::declval<Arg>()))>>: std::true_type {};

Может работать только на Fn с одним аргументом Я хочу создать FnOnArgs лайк

template<typename Fn, typename... Args, typename=void>
struct FnOnArgs;

но аргумент шаблона с переменным числом аргументов и аргумент по умолчанию должны быть последним аргументом Есть ли обходной путь для достижения FnOnArgs?

Почему бы просто не использовать std::is_invocable?

n. m. could be an AI 24.07.2024 09:33

В C++20 вы можете использовать requires и концепцию

Jarod42 24.07.2024 13:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
74
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы перемещаете фиктивный аргумент шаблона typename = void, чтобы он был где-то раньше typename... Args.

Это означает, что у него больше не может быть аргумента по умолчанию (= void), поэтому вы удаляете его и передаете void явно.

Затем вы создаете еще один шаблон, который оборачивает этот и автоматически добавляет void, поэтому вам не придется передавать его каждый раз.

template <typename Void, typename Fn, typename ...Args>
struct FnOnArgsLow : std::false_type {};

template <typename Fn, typename ...Args>
struct FnOnArgsLow<std::void_t<decltype(std::declval<Fn>()(std::declval<Args>()...))>, Fn, Args...> : std::true_type {};

// The wrapper can be a variable or a class, whatever you like more.
template <typename Fn, typename ...Args>
static constexpr bool FnOnArgs = FnOnArgsLow<void, Fn, Args...>::value;

Невозможно иметь параметр шаблона по умолчанию после пакета параметров.

Возможным решением может быть использование структуры-обертки, которая позволяет упаковывать вариативное количество параметров и затем передавать их как один аргумент. В данном случае для простоты использован std::tuple.

Пример:

namespace detail {
  template<typename, typename, typename = void>
  struct FnOnArg
   : std::false_type {};

  template<typename Fn, typename ...Args>
  struct FnOnArg<Fn, std::tuple<Args...>, std::void_t<decltype(std::declval<Fn>()(std::declval<Args...>()))>>
   : std::true_type {};
}

template <typename Fn, typename ...Args>
struct FnOnArg
 : detail::FnOnArg<Fn, std::tuple<Args...>> {};

Использование кортежа для этого является излишним. Меня немного беспокоят затраты времени на компиляцию. По крайней мере, я бы создал свой собственный класс списка типов.

HolyBlackCat 24.07.2024 10:03

Просто измените расположение параметров шаблона, как показано ниже:

template<typename Fn, typename=void, typename... Arg>
struct FnOnArg: std::false_type {};

template<typename Fn, typename... Arg>
struct FnOnArg<Fn, std::void_t<decltype(std::declval<Fn>()(std::declval<Arg>()...))>, Arg...>: std::true_type {};

//making an alias 
template<typename Fn, typename... Args>
constexpr static bool FnOnArg_v = FnOnArg<Fn, void, Args...>::value;

Рабочая демо

@HolyBlackCat Обновлено.

user12002570 24.07.2024 10:16

Другие вопросы по теме