I have a requirement that, I should use a specific class if an integer passed as one of the template parameter is greater than a certain value. Otherwise, I should get a compile time error...
It is something like the following:
enum Time { Day, Week, Month };
template<Time t, int length>
class Timer
{
}
Now, I have to restrict instantiating Timer
in such a way that -
Timer<Day,8>
, Timer<Day,9>
etc should work, but length
cannot be less than 8 when used with Day
.
Similarly, length
cannot be less than 10 when used with Week
and so on...
Can someone please help me out with how this can be achieved at compile-time?
All the template parameters are fixed+known at compile-time. If there are compiler errors due to template instantiation, they must be caught at compile-time!
Compile time parameters are parameters utilized during the compilation of a template. These parameters can only be used via the SparkleFormation library. It is for this reason that compile time parameters are generally discouraged from use.
3. What is the validity of template parameters? Explanation: Template parameters are valid inside a block only i.e. they have block scope.
Heavy use of templates can however lead to long compile times. Mostly right, but increased code size due to multiple instantiations of a template function can increase instruction cache misses, and slow down your program.
All of the other answers go for metaprogramming to detect the condition, I would on the other hand keep things simple:
template<Time t, int length>
class Timer
{
static_assert( (t == Day && length > 7)
||(t == Week && length > 10)
||(t == Month && length > 99), "Invalid parameters"
};
The compiler will trigger the assertion if the conditions are not met, and it is quite simple to verify by the error message and/or looking at the line.
Using SFINAE tools to disable versions of the type does also achieve the same result: the code will not compile, but at the cost of making the error messages more complex to read: what does it mean that Timer<Day,5>
is not a type? surely it is, it is the instantiation of Timer<Time,int>
!
EDIT: The above static_assert
is implemented in C++0x, in compilers without C++0x you can implement static_assert
as a macro:
#define static_assert( cond, name ) typedef char sassert_##name[ (cond)? 1 : -1 ];
This simple macro does not accept a string literal as second argument, but rather a single word. Usage would be:
static_assert( sizeof(int)==4, InvalidIntegerSize ) )
And error messages would require a bit of human parsing, as the compiler will complain (if the condition is not met) that the size of the sassert_InvalidIntegerSize
is negative.
Pass the result of length >= 8
as a bool
template argument to helper template. Provide specialization for true
only. Having said that, this sounds like homework, so I'll leave the coding to you.
Cheers & hth.
You can do this:
template<bool>
struct rule;
template<>
struct rule<true> {};
template<Time Tm, int Len>
struct constraint;
//Rule for Day
template<int Len>
struct constraint<Day, Len> : rule<(Len>= 8)>
{};
template<Time Tm, int Len>
class Timer : constraint<Tm, Len>
{
//your code
};
Test code:
int main() {
Timer<Day, 7> timer1; //error
Timer<Day, 8> timer2; //okay
return 0;
}
Online demos:
Timer<Day, 7> timer1
: commented )Timer<Day, 7> timer1
: not commented )Similarly, you can add rules for Week
and Month
as:
//Rule for Week
template<int Len>
struct constraint<Week, Len> : rule<(Len>= 10)>
{};
//Rule for Month
template<int Len>
struct constraint<Month, Len> : rule<(Len>= 100)>
{};
The idea for this kind of validation is generally to hand off the work to a dedicated helper class, which you specialize for each kind of parameters.
template <typename T, size_t V>
class Foo
{
static_assert(helper<T,V>::value, "Wrong Parameters");
};
There are two ways to perform the validation:
// Require full specialization
template <typename T, size_t V> struct helper: std::false_type {};
template <>
struct helper<Bar,0>: std::true_type {};
template <>
struct helper<Bar,4>: std::true_type {};
// Property like
template <typename T, size_t V> struct helper: std::false_type {};
template <size_t V>
struct helper<Bar, V>: std::integral_constant<bool, V <= 8> {};
Of course, those suppose C++0x facilities. In C++03, you'll have to provide the simple true_type
, false_type
and integral_constant
classes yourself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With