可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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;