How do I validate template parameters in compile time when a templated class contains no usable member functions?

匿名 (未验证) 提交于 2019-12-03 02:59:02

问题:

I have a following templated struct:

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

which is to be used like this:

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

now that template requires Degree to be non-negative. I'd like to enforce a compile-time assert for that.

How do I do that? I tried to add a destructor to CPowerOfTen:

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

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

How could I enforce a compile-time check for Degree being non-negative?

回答1:

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> {}; 


回答2:

You can use a uint. You won't get a compile time error but at least it will be self-documenting.



回答3:

You can use BOOST_STATIC_ASSERT macro. Or implement your own, the simplest way of forcing a failure is performing a typedef of an array of N elements, where N is positive/negative depending on the argument.

The problem with that approach is that it will produce a failure, but will try to perform the recursion nonetheless. Take a look at boost::enable_if_c to use SFINAE to fail instantiating the template if the argument is negative.



回答4:

You can forward the implementation to a class 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; } 


回答5:

How about implementing a STATIC_CHECK macro?

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;  


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!