使用整数模板参数时可以展开循环吗?

时间:2009-07-08 17:21:44

标签: c++ templates metaprogramming

我有以下代码:

template <int size>
inline uint hashfn( const char* pStr )
{
   uint result = *pStr;
   switch ( size )
   {
      case 10:
         result *= 4;
         result += *pStr;
      case 9:
         result *= 4;
         result += *pStr;
      ...
      ...
      case 2:
         result *= 4;
         result += *pStr;
   }
   return result;
}

此代码是某些长度的DNA序列的哈希函数,其中长度是模板参数。它是一个展开的循环,带有一个switch语句,可以在正确的位置跳转。 然而,大小是常量,因为它是模板参数。 我可以将它专门用于某些尺寸值吗? 也许有类似的东西:

template <int 2>
inline uint hashfn( const char* pStr )
{
  uint result = *pStr;
  result *= 4;
  ++pStr;
  result += *pStr;
  return result;
}

7 个答案:

答案 0 :(得分:3)

我倾向于使用模板递归地进行。

E.g。 :

template<class TOp,int factor>
struct recursive_unroll {
    __forceinline static void result( TOp& k ) {
        k();
        recursive_unroll<TOp,factor-1>::result( k );
    }
};

template<class TOp>
struct recursive_unroll<TOp,0> {
    __forceinline static void result( TOp& k ) {}
};


struct  op    {
    op( const char* s ) : res( 0 ), pStr( s )   {}

    unsigned int res;
    const char* pStr;        
    __forceinline void  operator()()  {
        res *= 4;
        res += *pStr;
        ++pStr;
        //std::cout << res << std::endl;
    }
};

char str[] = "dasjlfkhaskjfdhkljhsdaru899weiu";

int _tmain(int argc, _TCHAR* argv[])
{
    op tmp( str );
    recursive_unroll<op,sizeof( str ) >::result( tmp );
    std::cout << tmp.res << std::endl;
    return 0;
}

这为我提供了最佳代码。如果没有 __ forceinline ,代码就没有正确内联。

在使用此类优化之前,您应始终对代码进行测试。然后你应该看一下程序集并破译你的编译器已经为你做的事情。但在这种情况下,它似乎是一种推动力(对我而言)。


__ forceinline 是Microsoft Visual Studio特定的扩展程序。编译器应该生成最佳代码,但为此它不会。所以我在这里使用了这个扩展名。

答案 1 :(得分:1)

请阅读有关维基百科上的循环展开的信息。重点是保存循环变量的比较。你有没有对代码进行分析?与循环相比,我没有看到这样可以如何节省周期。

任何现代编译器都应该完全展开一个带有小静态循环计数的循环。

我也希望你不要使用基于模数的哈希表的哈希值,因为你将丢失哈希值的高位。

答案 2 :(得分:0)

原始代码中没有涉及循环,因此无法展开。

答案 3 :(得分:0)

你可以像这样专攻。但是,我认为您正专注于展开循环的优化。在您分析代码并显示它是瓶颈之前,最好不要过早地优化代码。

答案 4 :(得分:0)

  

我有以下代码:...(使用Duff设备的代码)......

     

这是一个展开的循环,带有一个switch语句,可以在正确的位置跳转。然而,大小是常量,因为它是模板参数。我可以针对某些尺寸值进行专门化吗?

你当然可以,但每种可能的尺寸都会涉及很多样板。通过适当的抽象级别,以及使用Boost metaprogrammingpreprocessor库,您甚至可以将其归结为合理的。

您的维护成本会上升,所以我会回应其他人并建议您确保 这样做可以

答案 5 :(得分:0)

我不知道语义是否正确,但在这种情况下,函数模板本身可以是递归的:

template <int size>
inline uint hashfn( const char* pStr ) {
    uint result = *pStr;
    result *= 4;
    return result + hashfn<size-1>(++pStr);
}

//case 0 stops
template <>
inline uint hashfn<0>( const char* pStr ) {
    return 0;
}

正如克里斯托弗所说,只要确保它被内联......

答案 6 :(得分:0)

代码

template <size_t N>
void
function (float *a, float *b, float *c)
{
  for (size_t i = 0; i < N; ++i)
    {
      c[i] = a[i] * b[i];
    }
}

我的编译器(msvc 2005,gcc 4.3)自动展开循环。