Reputation: 117
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?
Upvotes: 5
Views: 8004
Reputation: 208343
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.
Upvotes: 7
Reputation: 69988
enum Time { Day, Week, Month };
template<Time T> struct Length;
template<> struct Length<Day> { static const int value = 8 ; };
template<> struct Length<Week> { static const int value = 9; };
template<> struct Length<Month> { static const int value = 10; };
template<bool b> struct Limit;
template<> struct Limit<true> { typedef bool yes; };
#define COMPILE_ASSERT(V) typedef typename Limit<(V)>::yes checked
template<Time t, int length>
class Timer
{
COMPILE_ASSERT(length >= Length<t>::value);
};
See demo here.
Upvotes: 0
Reputation: 361412
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)>
{};
Upvotes: 3
Reputation: 299810
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.
Upvotes: 2
Reputation: 145269
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.
Upvotes: 6