About specialization with ints and static_assert

I want to write a template function that works only with two numbers (for example, 3 and 5), and gives errors if you try to use it with other numbers.

I can do it like this:

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 in the usual way:

 f<3>(); f<5>(); 

and it compiles well, and if I try to misuse my function:

 f<10>(); 

the compiler gives me an error.

I have 2 problems with this approach:

1.- Is this standard? Is it possible to specialize a template using ints?

2.- I do not like the error you get if you use this approach, because the error does not tell the user what he did wrong. I would rather write something like:

 template<int x> void f() { static_assert(false, "You are trying to use f with the wrong numbers"); } 

but it does not compile. It looks like my compiler (gcc 5.4.0) is trying to create the first primary template, and because of this it gives an error (static_assert).

Thank you for your help.

If you are wondering why I want to do this, this is because I am learning how to program a microcontroller. In the microcontroller, you have several contacts that only do some things. For example, pins 3 and 5 are pins in which you can create a square wave. If in the application I want to create a square wave, I want to write somthing like:

 square_wave<3>(frecuency); 

But if a few months later I want to reuse this code (or change it) in another application using another microcontroller, I want my compiler to tell me: "In this microcontroller, you cannot create a square wave in pins 3 and 5. Instead use contacts 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).

+5
source share
3 answers

1.- Is this standard? Is it possible to specialize a template using 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 condition of the static statement to something that depends 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"); } 

must work.


On the side, it is worth noting that it is usually considered not such a great idea to specialize function templates, since specialization interacts poorly (or at least somewhat unpredictably) with function overloading. Therefore, it is best to use a function object:

 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 that calls the function object:

 template <int I> void f(args...) { do_f<I>{}(args...); } 
+5
source

The static_assert condition static_assert always false , which makes the main template not selected when overload resolution is enabled before specs are selected. You can modify the static_assert condition to make it dependent on the tempalate x ..eg parameter

 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 template creation immediately after its definition will be poorly formed due to a design that is independent of the template parameter

...

Otherwise, for the template for which a valid specialization can be created, diagnostics should not be issued.

and $ 17.7.2 / 1 dependent names [temp.dep] :

Inside the template, some designs have semantics that may differ from one instance to another. This design depends on the template parameters.

+2
source

Other answers only offer a workaround. Moreover, this is due to the writing of template code. The easiest thing to do is

 template<int x> void f() = delete; 

Then you will get a good compiler error like

 error: call to deleted function 'f' 

when trying to create a template for a non-specialized int .

 #include <iostream> template<int x> void f() = delete; template<> void f<3>() { std::cout << "f<3>()\n"; } template<> void f<5>() { std::cout << "f<5>()\n"; } int main() { f<3>(); f<5>(); f<10>(); // BOOM! } 

Real time example

0
source

Source: https://habr.com/ru/post/1270545/


All Articles