Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 786
sharptooth Avatar asked Oct 07 '10 11:10

sharptooth


People also ask

Can a non templated class have a templated member function?

A non-template class can have template member functions, if required. Notice the syntax. Unlike a member function for a template class, a template member function is just like a free template function but scoped to its containing class.

Can we pass Nontype parameters to templates?

Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.

Can template parameters have default values?

Just like in case of the function arguments, template parameters can have their default values. All template parameters with a default value have to be declared at the end of the template parameter list.

Are templates compile time?

The use of templates can be thought of as compile-time polymorphism. The technique is used by a number of languages, the best-known being C++, but also Curl, D, Nim, and XL.


2 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> {};
like image 151
Alexey Malistov Avatar answered Sep 30 '22 02:09

Alexey Malistov


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

like image 31
DanDan Avatar answered Sep 30 '22 00:09

DanDan