Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

About specialization with ints, and static_assert

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).

like image 496
Antonio Avatar asked Aug 03 '17 16:08

Antonio


2 Answers

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...);
}
like image 56
Tristan Brindle Avatar answered Nov 03 '22 17:11

Tristan Brindle


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.

like image 2
songyuanyao Avatar answered Nov 03 '22 18:11

songyuanyao