使用int参数的意外模板行为:条件表达式被忽略?

J.K*_*eck 5 c++ templates

以下代码无法按预期工作(或至少如我所料).我尝试的所有g ++版本都在模板递归限制时失败.输出似乎表明条件语句被忽略,并且无论P的值如何,都使用最后的else块.

template <int P> inline REAL const_pow   ( REAL value );
template <     > inline REAL const_pow<0>( REAL value ) { return 1.0; }
template <     > inline REAL const_pow<1>( REAL value ) { return value; }
template <     > inline REAL const_pow<2>( REAL value ) { return value*value; }

template <int P> inline REAL const_pow   ( REAL value ) 
{
  if (P < 0)
    return const_pow<-P>( 1.0/value );
  else if (P % 2 == 0)
    return const_pow<2>( const_pow<P/2>(value) );
  else
    return value * const_pow<P-1>( value );
}
Run Code Online (Sandbox Code Playgroud)

问题似乎不是负值(排他性).如果我重新排序条件使得负值情况是最后一个,则每次仍然采用最后一个块.

我有一个使用辅助类和更复杂的专业化的工作解决方案.但是这个版本更具可读性并且应该达到相同的效果(启用优化).为什么不起作用?

Cyg*_*sX1 5

请记住,在实际执行开始之前,需要编译所有分支(在模板评估时进行评估)!因此,即使最终永远不会运行,const_pow<3>也会尝试实例化const_pow<-3>.这const_pow<3>又需要......

你需要的是完全禁用错误分支的模板评估.这可以通过手工制作的类型特征或通过C++ 11来解决std::enable_if.

请尝试以下方法:

#include <iostream>
typedef float REAL;

template <int P> inline REAL const_pow   ( REAL value );
template <     > inline REAL const_pow<0>( REAL value ) { return 1.0; }
template <     > inline REAL const_pow<1>( REAL value ) { return value; }
template <     > inline REAL const_pow<2>( REAL value ) { return value*value; }

template <int P, bool negative>
struct const_pow_helper { //instantiate this when P is positive
        static inline REAL call(REAL value) {
                return const_pow<2>(const_pow<P / 2>(value)) * const_pow<P % 2>(value);
        }
};

template <int P>
struct const_pow_helper<P, true> { //instantiate this when P is negative
        static inline REAL call(REAL value) {
                return const_pow_helper<-P, false>::call(1.0/value);
        }
};

template <int P> inline REAL const_pow   ( REAL value )
{
        return const_pow_helper<P, P<0 >::call(value);
}

int main() {
        std::cout << const_pow<10>(2.0f) << std::endl;
        std::cout << const_pow<-10>(2.0f) << std::endl;
};
Run Code Online (Sandbox Code Playgroud)

请注意,负面版本const_pow_helper将仅针对负面实例化P.此决定由模板评估者处理,而不是普通的if.

if用于正P被避免,以及,通过使用整数除法(P/2)和如果存在,剩余的值乘以(P%2).