Is it possible to conditionally compile a statement in a function based on the value of a template parameter? For example:
template<typename T, bool chk>
class subject
{
public:
// the ideal case
void doSomething(T new_val)
{
if(chk)
{
if(new_val != val)
//do_something only if new_val is different from val
}
else
{
//do_something even if new_val and val are equal
}
}
//or if that's not possible, if chk = 0 use this method
void doSomething(T new_val)
{
//do_something even if new_val and val are equal
}
// and if chk = 1 use this method
void doSomething(T new_val)
{
if(new_val != val)
//do_something only if new_val is different from val
}
T val;
};
the catch is based on the value of chk I don't even want the statement if(new_val!=val)
compiled into the function (because then every type T used would have to have a != operator defined).
I guess one drawback to this approach is that foo<int,0>
and foo<int,1>
are different classes so it wouldn't be possible to define a function that doesn't care if chk is 0 or 1 (say watch(foo<int>)
).
The application I'm looking at specifically is an observer and for some types I only want the observer to be notified if the value actually changes and for other types I want the observer to always be notified (and for those types I don't want to have to define a != operator).
Is this possible without having two separate classes?
Is this possible without having two separate classes?
Yes, it is. If you don't want to specialize your class, so as to avoid code repetition, you can use a sfinae expression like the one in the following example:
#include <type_traits>
#include <iostream>
template<typename T, bool chk>
struct subject {
template<bool trigger = chk>
std::enable_if_t<trigger>
doSomething(T new_val) {
if(new_val != val) {
std::cout << "new_val != val" << std::endl;
} else {
std::cout << "new_val == val" << std::endl;
}
}
template<bool trigger = chk>
std::enable_if_t<not trigger>
doSomething(T new_val) {
std::cout << "who cares?" << std::endl;
}
T val;
};
int main() {
subject<int, true> s1{0};
s1.doSomething(0);
s1.doSomething(1);
subject<int, false> s2{0};
s2.doSomething(0);
s2.doSomething(1);
}
The idea is that the right definition for doSomething
is picked up at compile time and it depends on the value of the template parameter chk
. The other definition is simply discarded as expected and won't be available at all.
Note that, for the sfinae expression to work, the trigger
template parameter must be an actual parameter of the member function template. That's why you have to define it this way:
template<bool trigger = chk>
sfinae_expression_based_on_enable_if
doSomething(T new_val) { /* ... */ }
See it on running on coliru.
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