I want to write a template function that only work with 2 numbers (for instance 3 and 5) and gives and error if you try to use it with another numbers.
I can do this in this way:
template<int x>
void f();
template<>
void f<3>()
{
cout << "f<3>()\n";
}
template<>
void f<5>()
{
cout << "f<5>()\n";
}
and then I can call this function the normal way:
f<3>();
f<5>();
and it compiles well, and if I try to use my function incorrectly:
f<10>();
the compiler gives me an error.
I have 2 problems with this approach:
1.- Is this standard? Can I specialized a template with ints?
2.- I don't like the error you get if you use this approach, because the error doesn't tell the user what he had done incorrectly. I'd prefer write something like:
template<int x>
void f()
{
static_assert(false, "You are trying to use f with the wrong numbers");
}
but this doesn't compile. It appears my compiler (gcc 5.4.0) is trying to instantiate first the primary template, and because of that it gives the error (of the static_assert).
Thank you for your help.
In case you are wondering why I want to do this is because I am learning how to program a microcontroller. In a microcontroller you have some pins that only do some things. For instance, the pins 3 and 5 are the pins in which you can generate a square wave. If in an application I want to generate a square wave I want to write somthing like:
square_wave<3>(frecuency);
But, if some months later I want to reuse this code (or change it) in another application with a differente microcontroller, I want my compiler say to me: "eh, in this microcontroller you can't generate a square wave in pins 3 and 5. Instead, use pins 7 and 9". And I think this can save me a lot of headaches (or maybe not, I really don't know. I'm just learning how to program a microcontroller).
1.- Is this standard? Can I specialized a template with ints?
Yes.
2.
template<int x>
void f()
{
static_assert(false, "You are trying to use f with the wrong numbers");
}
You need to change the static assert condition into something that is dependent on the value of the template parameter. Something as simple as
template <int x>
void f()
{
static_assert(x - x, "You are trying to use f with the wrong numbers");
}
should work.
As an aside, it's worth noting that it's usually considered not such a great idea to specialise function templates, as specialisation interacts badly (or at least somewhat unpredictably) with function overloading. So it may be a better idea in general to use a function object instead:
template <int I>
struct do_f {
static_assert(I - I, "You are trying to use f with the wrong numbers");
};
template <>
struct do_f<3> {
void operator()(args...) { ... }
};
template <>
struct do_f<5> {
void operator()(args...) { ... }
};
Then you can write a wrapper function which calls out to the function object:
template <int I>
void f(args...) {
do_f<I>{}(args...);
}
The condition of static_assert
is always false
, that make the primary template failing to be selected in overload resolution, before the selection of the specifications. You can change the condition of static_assert
to make it depending on the tempalate parameter x
. .e.g
template<int x>
void f()
{
static_assert(x == 3 || x == 5, "You are trying to use f with the wrong numbers");
}
LIVE
From the standard, $17.7/8,9 Name resolution [temp.res]:
a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter
...
Otherwise, no diagnostic shall be issued for a template for which a valid specialization can be generated.
and $17.7.2/1 Dependent names [temp.dep]:
Inside a template, some constructs have semantics which may differ from one instantiation to another. Such a construct depends on the template parameters.
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