c++ - Unexpected template behavior with int parameter: conditional expressions ignored? -
the following code not work expected (or @ least expected). versions of g++ tried fail @ template recursion limit. output seems indicate conditional statements ignored , final else block used regardless of value of p.
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 ); }
the problem doesn't seem negative values (exclusively.) if re-order conditional such negative-value case last, last block still taken every time.
i have working solution using helper class , more complex specialization. version lot more readable , should achieve same effect (with optimization enabled). why doesn't work?
keep in mind all branches need compiled (evaluated @ template-evaluation time) before actual execution begins! reason, const_pow<3>
try instantiate const_pow<-3>
if never run. in return requires const_pow<3>
again...
what need disable template evaluation of incorrect branch alltogether. can resolved either through manually crafted type-traits, or through c++11 std::enable_if
.
try following:
#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 when p 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 when p 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; };
notice negative version of const_pow_helper
instantiated negative p
. decision handled template evaluator , not ordinary if
.
the if
positive p
has been avoided well, using integer division (p/2)
, multiplying remainder value if exists (p%2)
.
Comments
Post a Comment