C++将变量转换为模板参数

Mic*_*pso 7 c++ templates c++11

我想描述使用模板优化这里.但是,随着bool模板参数的增加,实例化模板可能会有太多分支.如果你使用更大的枚举而不是bools,它会变得更加冗长.

#include <iostream>
using namespace std;

template <bool b1, bool b2>
int HeavyLoop_impl(int arg)
{
    for (int i = 0; i < 10000000; i++)
    {
        // b1 is known at compile-time, so this branch will be eliminated
        if (b1) { arg += 1; }
        else    { arg += 2; }

        // b2 is known at compile-time, so this branch will be eliminated
        if (b2) { arg += 10; }
        else    { arg += 20; }
    }
    return arg;
}

// This function could be 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;
}
Run Code Online (Sandbox Code Playgroud)

有没有办法自动生成HeavyLoop功能?我想要这样的东西:

vars_to_template_function<bool, bool>(HeavyLoop_impl, b1, b2, arg);
Run Code Online (Sandbox Code Playgroud)

这有可能以某种方式吗?谢谢你的任何提示.

注意:这只是一个非常简单的例子.实际循环当然更复杂:o)

Dan*_*rey 5

我决定对代码进行更多的乐趣,这是我第一次尝试后的改进版本,具有以下优点:

  • 支撑enum类型
  • 明确指定应转换的参数数量
  • 复杂部分的通用实现,每个使用它的函数都有一个小助手。

代码:

#include <iostream>
#include <utility>
#include <type_traits>

// an enum we would like to support
enum class tribool { FALSE, TRUE, FILE_NOT_FOUND };

// declare basic generic template
// (independent of a specific function you'd like to call)
template< template< class > class CB, std::size_t N, typename = std::tuple<> >
struct var_to_template;

// register types that should be supported
template< template< class > class CB, std::size_t N, typename... Cs >
struct var_to_template< CB, N, std::tuple< Cs... > >
{
    // bool is pretty simple, there are only two 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 )... );
    }

    // for each enum, you need to register all its 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 you could also add int, long, ... but
    // you'd have to switch on every possible value that you want to support!
};

// terminate the 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 your function with the template parameters
template< bool B, tribool TB >
int HeavyLoop_impl( int arg )
{
    for( int i = 0; i < 10000000; i++ ) {
        arg += B ? 1 : 2;
        arg += ( TB == tribool::TRUE ) ? 10 : ( TB == tribool::FALSE ) ? 20 : 30;
    }
    return arg;
}

// a helper class, required once per function that you'd like to 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 )... );
    }
};

// and here, everything comes together:
int HeavyLoop( bool b, tribool tb, int arg )
{
    // you provide the helper and the number of arguments
    // that should be converted to var_to_template<>
    // and you provide the return type to 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;
}
Run Code Online (Sandbox Code Playgroud)

如果您想使用它,这里有一个实时示例