C++ convert variables to template arguments -
i use templates optimization described here. however, growing number of bool template arguments, instantiating template might have many branches. , gets more branchy if use larger enums instead of bools.
#include <iostream> using namespace std; template <bool b1, bool b2> int heavyloop_impl(int arg) { (int = 0; < 10000000; i++) { // b1 known @ compile-time, branch eliminated if (b1) { arg += 1; } else { arg += 2; } // b2 known @ compile-time, branch eliminated if (b2) { arg += 10; } else { arg += 20; } } return arg; } // function generated automatically void heavyloop(bool b1, bool b2, int arg) { int res; if (b1) { if (b2) { res = heavyloop_impl<true, true>(arg); } else { res = heavyloop_impl<true, false>(arg); } } else { if (b2) { res = heavyloop_impl<false, true>(arg); } else { res = heavyloop_impl<false, false>(arg); } } cout << "res: "<<res<<endl; } int main(int argc, char**argv) { bool b1 = true; bool b2 = false; int arg = 0; heavyloop(b1, b2, arg); return 0; }
is there way automatically generate heavyloop function? this:
vars_to_template_function<bool, bool>(heavyloop_impl, b1, b2, arg);
would possible somehow? hints.
note: simplified example. actual loop is of course more complicated :o)
i decided have more fun code, here's improved version on first attempt has following benefits:
- supports
enum
types - explicitly specify how many parameters should converted
- generic implementation complicated part, 1 small helper each function uses it.
the code:
#include <iostream> #include <utility> #include <type_traits> // enum support enum class tribool { false, true, file_not_found }; // declare basic generic template // (independent of specific function you'd call) template< template< class > class cb, std::size_t n, typename = std::tuple<> > struct var_to_template; // register types should supported template< template< class > class cb, std::size_t n, typename... cs > struct var_to_template< cb, n, std::tuple< cs... > > { // bool pretty simple, there 2 values template< typename r, typename... args > static r impl( bool b, args&&... args ) { return b ? var_to_template< cb, n-1, std::tuple< cs..., std::true_type > >::template impl< r >( std::forward< args >( args )... ) : var_to_template< cb, n-1, std::tuple< cs..., std::false_type > >::template impl< r >( std::forward< args >( args )... ); } // each enum, need register values template< typename r, typename... args > static r impl( tribool tb, args&&... args ) { switch( tb ) { case tribool::false: return var_to_template< cb, n-1, std::tuple< cs..., std::integral_constant< tribool, tribool::false > > >::template impl< r >( std::forward< args >( args )... ); case tribool::true: return var_to_template< cb, n-1, std::tuple< cs..., std::integral_constant< tribool, tribool::true > > >::template impl< r >( std::forward< args >( args )... ); case tribool::file_not_found: return var_to_template< cb, n-1, std::tuple< cs..., std::integral_constant< tribool, tribool::file_not_found > > >::template impl< r >( std::forward< args >( args )... ); } throw "unreachable"; } // in theory add int, long, ... // you'd have switch on every possible value want support! }; // terminate recursion template< template< class > class cb, typename... cs > struct var_to_template< cb, 0, std::tuple< cs... > > { template< typename r, typename... args > static r impl( args&&... args ) { return cb< std::tuple< cs... > >::template impl< r >( std::forward< args >( args )... ); } }; // here's function template parameters template< bool b, tribool tb > int heavyloop_impl( int arg ) { for( int = 0; < 10000000; i++ ) { arg += b ? 1 : 2; arg += ( tb == tribool::true ) ? 10 : ( tb == tribool::false ) ? 20 : 30; } return arg; } // helper class, required once per function you'd forward template< typename > struct heavyloop_callback; template< typename... cs > struct heavyloop_callback< std::tuple< cs... > > { template< typename r, typename... args > static r impl( args&&... args ) { return heavyloop_impl< cs::value... >( std::forward< args >( args )... ); } }; // , here, comes together: int heavyloop( bool b, tribool tb, int arg ) { // provide helper , number of arguments // should converted var_to_template<> // , provide return type impl<> return var_to_template< heavyloop_callback, 2 >::impl< int >( b, tb, arg ); } int main() { bool b = true; tribool tb = tribool::false; int arg = 0; int res = heavyloop( b, tb, arg ); std::cout << "res: " << res << std::endl; return 0; }
and here's live example in case want play it.
Comments
Post a Comment