Сопоставление значений времени выполнения с типами шаблонов слишком далеко - PullRequest
1 голос
/ 11 июля 2020

Я работаю над пользовательской структурой 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");
    };
}

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

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

EDIT:

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

...