adapting a non-constexpr integral value to a non-type template parameter, and code bloat

前端 未结 4 1447
梦毁少年i
梦毁少年i 2021-01-13 03:03

Consider a function object F taking a constexpr size_t argument I

struct F
{
    template 
    constex         


        
4条回答
  •  不思量自难忘°
    2021-01-13 03:32

    I call this technique the magic switch.

    The most efficient way I know of to do this is to build your own jump table.

    // first, index list boilerplate.  Does log-depth creation as well
    // needed for >1000 magic switches:
    template struct indexes {typedef indexes type;};
    template struct concat_indexes;
    template struct concat_indexes, indexes>{
        typedef indexes type;
    };
    template
    using ConcatIndexes = typename concat_indexes::type;
    
    template struct make_indexes:
        ConcatIndexes<
            typename make_indexes::type,
            typename make_indexes::type
        >
    {};
    template struct make_indexes:
        indexes<>
    {};
    template struct make_indexes:
        indexes
    {};
    template
    using MakeIndexes = typename make_indexes::type;
    
    // This class exists simply because [](blah){code}... `...` expansion
    // support is lacking in many compilers:
    template< typename L, typename R, unsigned I >
    struct helper_helper {
        static R func( L&& l ) { return std::forward(l)(size()); }
    };
    // the workhorse.  Creates an "manual" jump table, then invokes it:
    template
    auto
    dispatch_helper(indexes, L&& l, unsigned i)
    -> decltype( std::declval()(size<0>()) )
    {
      // R is return type:
      typedef decltype( std::declval()(size<0>()) ) R;
      // F is the function pointer type for our jump table:
      typedef R(*F)(L&&);
      // the jump table:
      static const F table[] = {
        helper_helper::func...
      };
      // invoke at the jump spot:
      return table[i]( std::forward(l) );
    };
    // create an index pack for each index, and invoke the helper to
    // create the jump table:
    template
    auto
    dispatch(L&& l, unsigned i)
    -> decltype( std::declval()(size<0>()) )
    {
      return dispatch_helper( MakeIndexes(), std::forward(l), i );
    };
    

    which requires some static setup, but is pretty fast when run.

    An assert that i is in bounds may also be useful.

    live example

提交回复
热议问题