Сопоставление значений времени выполнения с типами шаблонов слишком далеко

Я работаю над настраиваемой структурой FFI для языка и сталкиваюсь с проблемой необходимости создания экземпляров шаблонов во всех возможных ветвях сравнения. Когда это становится рекурсивным, количество экземпляров (и время компиляции) резко возрастает. Реализация выглядит так:

template<template<typename...> class F, typename ... Args>
struct TypeApp{
    template<typename ... UArgs>
    static auto apply(Type t, UArgs &&... uargs){
        // all of the templates in these branches will be instantiated
        if(t == type_<void>){ return F<Args..., void>::apply(std::forward<UArgs>(uargs)...); }
        else if(t == type_<bool>){ return F<Args..., bool>::apply(std::forward<UArgs>(uargs)...); }
        else if(t == type_<int>){ return F<Args..., int>::apply(std::forward<UArgs>(uargs)...); }
        // ...
        else{ assert(!"unrepresentable type"); }
    }
};

template<typename...> struct FFICaller;

template<std::size_t ParamsRem, typename Ret, typename ... Params>
struct FFICaller<std::integral_constant<std::size_t, ParamsRem>, Ret, Params...>{
    static auto apply(std::span<Type> params){
        return TypeApp<FFICaller, std::integral_constant<std::size_t, ParamsRem-1>, Ret, Params...>
                ::apply(params[0], params.subspan(1));
    }
};

template<typename Ret, typename ... Params>
struct FFICaller<std::integral_constant<std::size_t, 0>, Ret, Params...>{
    static FFIFn apply(){
        return +[](void *ptr, const std::vector<Value> &args){
            // call 'ptr' with 'args'
        };
    }
};

Итак, когда я пытаюсь сделать что-то вроде этого:

void doFFIStuff(void *ptr, Type result, const std::vector<Type> &params){
    FFIFn fn;
    switch(params.size()){
        case 1: fn = TypeApp<FFICaller, std::integral_constant<std::size_t, 1>>::apply(result, params); break;
        case 2: fn = TypeApp<FFICaller, std::integral_constant<std::size_t, 2>>::apply(result, params); break;
        case 3: fn = TypeApp<FFICaller, std::integral_constant<std::size_t, 3>>::apply(result, params); break;
        case 4: fn = TypeApp<FFICaller, std::integral_constant<std::size_t, 4>>::apply(result, params); break;
        default: assert(!"only up to 4 arguments currently supported");
    };
}

Мой компилятор замирает в ужасе от горы кода, который ему приходится обрабатывать.

Есть ли способ реструктурировать этот код, чтобы он не создавал экземпляры каждой ветки несколько раз?

РЕДАКТИРОВАТЬ:

Вот минимальный пример Godbolt, где, если вы закомментируете случаи 4 и 5 переключателя в getFFIFn, он будет компилировать.


person RamblingMad    schedule 11.07.2020    source источник
comment
Вы имели в виду return TypeApp<FFICaller, std::integral_constant<std::size_t, ParamsRem - 1>, /*...*/?   -  person Piotr Skotnicki    schedule 11.07.2020
comment
И это не решает проблему?   -  person Piotr Skotnicki    schedule 11.07.2020
comment
@PiotrSkotnicki нет, просто ошибка копирования кода   -  person RamblingMad    schedule 11.07.2020
comment
Создайте правильный MCVE (например, на coliru, godbolt или wandbox) и укажите на него ссылку в своем вопросе. В противном случае мы можем только догадываться, могут ли наши предложения вам помочь (как это сделал @Piotr).   -  person ildjarn    schedule 11.07.2020
comment
Боковое примечание: вы, вероятно, могли бы заменить это перечисление вариантом типов прокси. Могу вырезать значительную часть кода. Это означает выполнение таких действий, как в stackoverflow.com/a/62780979/5684257 и stackoverflow.com/a/61310826/5684257   -  person HTNW    schedule 11.07.2020
comment
Известны ли используемые вами функции (например, std :: fmaf) во время компиляции?   -  person Benny K    schedule 21.07.2020
comment
@BennyK в каком контексте?   -  person RamblingMad    schedule 21.07.2020
comment
Вы выбрали std::vector<Type> для paramTypes и сильно полагаетесь на утверждения if и switch. Можно ли их заменить на std::array? Всегда ли вы знаете количество аргументов и их типы во время компиляции?   -  person Benny K    schedule 21.07.2020
comment
@BennyK FFI предназначен для интерпретатора, который может вызывать произвольные функции C, поэтому он не всегда может быть известен. В качестве резервной копии я сейчас использую только libffi.   -  person RamblingMad    schedule 21.07.2020