How to check template parameters at compile time when a template class does not contain useful member functions?

I have the following boilerplate struct :

 template<int Degree> struct CPowerOfTen { enum { Value = 10 * CPowerOfTen<Degree - 1>::Value }; }; template<> struct CPowerOfTen<0> { enum { Value = 1 }; }; 

which should be used as follows:

 const int NumberOfDecimalDigits = 5; const int MaxRepresentableValue = CPowerOfTen<NumberOfDecimalDigits>::Value - 1; // now can use both constants safely - they're surely in sync 

Now the template requires Degree be non-negative. I would like to provide a compile time statement for this.

How can I do it? I tried adding a destructor to CPowerOfTen :

 ~CPowerOfTen() { compileTimeAssert( Degree >= 0 ); } 

but since it is not called directly, Visual C ++ 9 decides not to instantiate it, so the compert-time assert statement is not evaluated at all.

How can I make the compile time check for Degree non-negative?

+6
c ++ visual-c ++ templates metaprogramming
source share
5 answers
 template<bool> struct StaticCheck; template<> struct StaticCheck<true> {}; template<int Degree> struct CPowerOfTen : StaticCheck<(Degree > 0)> { enum { Value = 10 * CPowerOfTen<Degree - 1>::Value }; }; template<> struct CPowerOfTen<0> { enum { Value = 1 }; }; 

Edit: without infinite recursion.

 // Help struct template<bool, int> struct CPowerOfTenHelp; // positive case template<int Degree> struct CPowerOfTenHelp<true, Degree> { enum { Value = 10 * CPowerOfTenHelp<true, Degree - 1>::Value }; }; template<> struct CPowerOfTenHelp<true, 0> { enum { Value = 1 }; }; // negative case template<int Degree> struct CPowerOfTenHelp<false, Degree> {} // Main struct template<int Degree> struct CPowerOfTen : CPowerOfTenHelp<(Degree >= 0), Degree> {}; 
+8
source share

You can use uint. You will not get a compile-time error, but at least it will be self-documenting.

+5
source share

You can use the macro BOOST_STATIC_ASSERT . Or implement your own, the easiest way to force a failure - to execute a typedef from an array of N elements, where N is positively / negatively dependent on the argument.

The problem with this approach is that it will crash, but will try to recurs. See boost::enable_if_c to use SFINAE to refuse to instantiate a template if the argument is negative.

+5
source share

You can redirect the implementation to a class by also accepting a bool parameter indicating whether the result can be calculated.

 #include <limits> template <int Degree, bool InRange> struct PowerOfTenImpl { enum {Value = 10 * PowerOfTenImpl<Degree - 1, InRange>::Value}; }; template <> struct PowerOfTenImpl<0, true> { enum {Value = 1}; }; template <int Degree> struct PowerOfTenImpl<Degree, false> { }; template<int Degree> struct CPowerOfTen { enum { Value = PowerOfTenImpl<Degree, Degree >= 0 && Degree <= std::numeric_limits<int>::digits10>::Value }; }; int main() { const int a = CPowerOfTen<4>::Value; const int b = CPowerOfTen<1000>::Value; const int c = CPowerOfTen<-4>::Value; } 
+2
source share

How to implement the macro STATIC_CHECK ?

 template<bool> struct CompileTimeError; template<> struct CompileTimeError<true> {}; //specialized only for true #define STATIC_CHECK(expr) (CompileTimeError<(expr) != 0>()) 

Inside main()

  const int NumberOfDecimalDigits = -1; STATIC_CHECK(NumberOfDecimalDigits > 0); // Error : invalid use of incomplete type struct CompileTimeError<false> const int MaxRepresentableValue = CPowerOfTen<NumberOfDecimalDigits>::Value - 1; 
+1
source share

All Articles