Switch statement variadic template expansion

后端 未结 2 736
春和景丽
春和景丽 2020-12-09 20:57

Let me please consider the following synthetic example:

inline int fun2(int x) {
    return x;
}
inline int fun2(double x) {
    return 0;   
}
inline int fu         


        
2条回答
  •  無奈伤痛
    2020-12-09 21:27

    Ok, I rewrote my answer. This gives a different approach to what TartanLlama and also what I suggested before. This meets your complexity requirement and doesn't use function pointers so everything is inlineable.

    Edit: Much thanks to Yakk for pointing out a quite significant optimization (for the compile-time template recursion depth required) in comments

    Basically I make a binary tree of the types / function handlers using templates, and implement the binary search manually.

    It might be possible to do this more cleanly using either mpl or boost::fusion, but this implementation is self-contained anyways.

    It definitely meets your requirements, that the functions are inlineable and runtime look up is O(log n) in the number of types in the tuple.

    Here's the complete listing:

    #include 
    #include 
    #include 
    #include 
    
    using std::size_t;
    
    // Basic typelist object
    template
    struct TypeList{
       static const int size = sizeof...(TL);
    };
    
    // Metafunction Concat: Concatenate two typelists
    template
    struct Concat;
    
    template
    struct Concat , TypeList> {
        typedef TypeList type;
    };
    
    template
    using Concat_t = typename Concat::type;
    
    // Metafunction First: Get first type from a typelist
    template
    struct First;
    
    template
    struct First > {
        typedef T type;
    };
    
    template
    using First_t = typename First::type;
    
    
    // Metafunction Split: Split a typelist at a particular index
    template
    struct Split;
    
    template
    struct Split> {
    private:
        typedef Split> FirstSplit;
        typedef Split SecondSplit;
    public:
        typedef Concat_t L;
        typedef typename SecondSplit::R R;
    };
    
    template
    struct Split<0, TypeList> {
        typedef TypeList<> L;
        typedef TypeList R;
    };
    
    template
    struct Split<1, TypeList> {
        typedef TypeList L;
        typedef TypeList R;
    };
    
    template
    struct Split> {
        typedef TypeList<> L;
        typedef TypeList<> R;
    };
    
    
    // Metafunction Subdivide: Split a typelist into two roughly equal typelists
    template
    struct Subdivide : Split {};
    
    // Metafunction MakeTree: Make a tree from a typelist
    template
    struct MakeTree;
    
    /*
    template<>
    struct MakeTree> {
        typedef TypeList<> L;
        typedef TypeList<> R;
        static const int size = 0;
    };*/
    
    template
    struct MakeTree> {
        typedef TypeList<> L;
        typedef TypeList R;
        static const int size = R::size;
    };
    
    template
    struct MakeTree> {
    private:
        typedef TypeList MyList;
        typedef Subdivide MySubdivide;
    public:
        typedef MakeTree L;
        typedef MakeTree R;
        static const int size = L::size + R::size;
    };
    
    // Typehandler: What our lists will be made of
    template
    struct type_handler_helper {
        typedef int result_type;
        typedef T input_type;
        typedef result_type (*func_ptr_type)(const input_type &);
    };
    
    template::func_ptr_type me>
    struct type_handler {
        typedef type_handler_helper base;
        typedef typename base::func_ptr_type func_ptr_type;
        typedef typename base::result_type result_type;
        typedef typename base::input_type input_type;
    
        static constexpr func_ptr_type my_func = me;
        static result_type apply(const input_type & t) {
            return me(t);
        }
    };
    
    // Binary search implementation
    template 
    struct apply_helper;
    
    template 
    struct apply_helper {
        template
        static int apply(const V & v, size_t index) {
            assert(index == 0);
            return First_t::apply(v);
        }
    };
    
    template 
    struct apply_helper {
        template
        static int apply(const V & v, size_t index) {
            if( index >= T::L::size ) {
                return apply_helper::apply(v, index - T::L::size);
            } else {
                return apply_helper::apply(v, index);
            }
        }
    };
    
    // Original functions
    
    inline int fun2(int x) {
        return x;
    }
    inline int fun2(double x) {
        return 0;   
    }
    inline int fun2(float x) {
        return -1;   
    }
    
    // Adapted functions
    typedef std::tuple tup;
    
    inline int g0(const tup & t) { return fun2(std::get<0>(t)); }
    inline int g1(const tup & t) { return fun2(std::get<1>(t)); }
    inline int g2(const tup & t) { return fun2(std::get<2>(t)); }
    
    // Registry
    
    typedef TypeList<
       type_handler,
       type_handler,
       type_handler
    > registry;
    
    typedef MakeTree jump_table;
    
    int apply(const tup & t, size_t index) {
        return apply_helper::apply(t, index);
    }
    
    // Demo
    
    int main() {
        {
            tup t{5, 1.5, 15.5f};
    
            std::cout << apply(t, 0) << std::endl;
            std::cout << apply(t, 1) << std::endl;
            std::cout << apply(t, 2) << std::endl;
        }
    
        {
            tup t{10, 1.5, 15.5f};
    
            std::cout << apply(t, 0) << std::endl;
            std::cout << apply(t, 1) << std::endl;
            std::cout << apply(t, 2) << std::endl;
        }
    
        {
            tup t{15, 1.5, 15.5f};
    
            std::cout << apply(t, 0) << std::endl;
            std::cout << apply(t, 1) << std::endl;
            std::cout << apply(t, 2) << std::endl;
        }
    
        {
            tup t{20, 1.5, 15.5f};
    
            std::cout << apply(t, 0) << std::endl;
            std::cout << apply(t, 1) << std::endl;
            std::cout << apply(t, 2) << std::endl;
        }
    }
    

    Live on Coliru: http://coliru.stacked-crooked.com/a/3cfbd4d9ebd3bb3a

提交回复
热议问题