Я работаю над пользовательской структурой 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> ¶ms){
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");
};
}
Мой компилятор замирает в ужасе от огромного количества кода, который ему приходится обрабатывать.
Есть ли способ реструктурировать этот код, чтобы он не создавал экземпляры каждой ветки несколько раз?
EDIT:
Вот минимальный пример godbolt где, если вы закомментируете варианты 4 и 5 из переключателя в getFFIFn
, он будет компилироваться.