Можно ли автоматически сопоставлять и перенаправлять типы в контексте структуры на параметры функции с помощью шаблонов C++?

Скажем, у меня есть структура как контекст данных, определенный следующим образом:

struct Ctx {
   TypeA a;
   TypeB b;
   TypeC c;
   TypeD d;
   TypeE e;
};

auto TestFunc(TypeA a, TypeB b, TypeC c, args...) -> result;

И вызов будет иметь форму:

TestFunc(ctx.a, ctx.b, ctx.c, args...);

Поскольку ctx избыточен, мне нужна новая оболочка:

auto TestFunc(Ctx& ctx, args...) -> result {
    return TestFunc(ctx.a, ctx.b, ctx.c, args...);
}

Есть ли способ сопоставить сигнатуру типа функции с сигнатурой типа структуры, чтобы я мог создать какую-то комбинацию макросов и универсальных шаблонов, которая будет работать без необходимости вручную писать оболочку для каждой функции, которая обращается к членам в этом Ctx?

Не можешь изменить TestFunc ? Я думаю, что вы пытаетесь решить проблему не с той стороны. Если функция имеет много параметров, вам нужно исправить эту функцию.

463035818_is_not_a_number 15.02.2023 11:04

Являются ли функции вариативными? Или ... просто заполнитель в вашем примере, чтобы проиллюстрировать, что параметров больше?

463035818_is_not_a_number 15.02.2023 11:08

Можно ли заменить/преобразовать структуру Ctx в пару? std::apply может быть решением, если это так.

Ignacio Gaviglio 15.02.2023 12:12

Первый вопрос: нет, я не могу изменить TestFunc, кроме как обернув его, это библиотека C. Я просто хочу избежать ручной упаковки, потому что есть сотни функций, которые принимают эту форму. Второй вопрос: Да, это также вариативно, поэтому я пересылаю все конечные параметры.

JimmyStack 15.02.2023 12:12

Игнасио, я не слишком внимательно изучал кортежи, это может быть вариантом. Я проверю это, спасибо!

JimmyStack 15.02.2023 12:25
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Настройка шаблона Metronic с помощью Webpack и Gulp
Настройка шаблона Metronic с помощью Webpack и Gulp
Я пишу эту статью, чтобы поделиться тем, как настроить макет Metronic с помощью Sass, поскольку Metronic предоставляет так много документации, и они...
Уроки CSS 6
Уроки CSS 6
Здравствуйте дорогие читатели, я Ферди Сефа Дюзгюн, сегодня мы продолжим с вами уроки css. Сегодня мы снова продолжим с так называемых классов.
Что такое Css? Для чего он используется?
Что такое Css? Для чего он используется?
CSS, или "Каскадные таблицы стилей", - это язык стилей, используемый в веб-страницах. CSS является одним из основных инструментов веб-разработки...
0
5
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я не совсем уверен, чего вы хотите достичь.

Но, возможно, вариативное struct поможет. Вы можете получить элементы структуры из значений инициализации. Конечно, возможны и другие вычеты.

Мы можем построить вариативную структуру на std::tuple. И мы можем перегрузить оператор вызова функции и использовать std::apply для вызова функции с элементами вариативного struct.

См., например, следующее решение:

#include <iostream>
#include <functional>
#include <tuple>

// Variadic struct
template <typename...Args>
struct Ctx {
    // Variadic data
    std::tuple<Args...> data{};  
    // Variadic Constructor. Will use CTAD
    Ctx(Args...args) : data(std::forward<decltype(args)>(args)...) {};
    // Calling the function with the data of the struct
    void operator()(std::function<void(Args...)> f) {
        std::apply(f,data);
    }
};

// Your library function
void print(int i, char c, double d) {
    std::cout << i << ' ' << c << ' ' << d << '\n';
}
// Test code
int main() {

    Ctx v(1, 'a', 1.1);
    
    v (print);
}

Конечно, возможны и другие реализации. Пожалуйста, прокомментируйте, если вам нужно что-то еще.

Чего я хочу добиться, так это того, что у меня есть контекст, который содержит кэшированные дескрипторы разных типов. Существуют сотни функций, которые могут работать с различными элементами. Я хочу обернуть их все, поэтому я просто передаю контекст, и он перенаправляет соответствующие члены (по типу) в функцию, чтобы упростить использование библиотеки. Таким образом, мне не нужно писать сотни оболочек функций, выбирая подходящие члены для передачи вручную. Предложения, которые я видел до сих пор, похоже, требуют передачи ВСЕХ членов, я хочу передать только те, которые соответствуют сигнатуре типа функции.

JimmyStack 15.02.2023 15:21

Другими словами, если функция принимает члены типа X и типа Z, но не типа Y, я хочу передать X и Z. Я не уверен, что это возможно, поэтому и спросил. Должен уточнить: я знаю, что мне придется выполнить некоторую работу с оболочкой, но если бы я мог преобразовать ее в макрос/шаблон, чтобы для каждой функции был только один вкладыш, тогда я был бы доволен этим.

JimmyStack 15.02.2023 15:28
Ответ принят как подходящий

Как я понимаю, вам нужно 2 вещи:

  • одна (или две с const) функция для преобразования вашей структуры в кортеж:
struct Ctx {
   auto as_tuple() const { return std::tie(a, b, c, d, e); }
   auto as_tuple() { return std::tie(a, b, c, d, e); }

   TypeA a;
   TypeB b;
   TypeC c;
   TypeD d;
   TypeE e;
};

Тогда, предполагая, что типы различны, функция (или 2 для поддержки C-многоточия) для фильтрации из кортежа только нужного аргумента:

template <typename Tuple, typename Ret, typename... Ts, typename... Args>
Ret call(Ret(*func)(Ts...), Tuple&& tuple, Args&&... args)
{
    return func(std::get<Ts&>(tuple)..., std::forward<Args>(args)...);
}

template <typename Tuple, typename Ret, typename... Ts, typename... Args>
Ret call(Ret(*func)(Ts..., ...), Tuple&& tuple, Args&&... args)
{
    return func(std::get<Ts&>(tuple)..., std::forward<Args>(args)...);
}

Демо

Кажется, это именно то, что я ищу. Спасибо!

JimmyStack 15.02.2023 21:03

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