Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Short Circuiting Operators in an enable_if

I want to write a templatized function which takes either an array<int, 3> or an int[3]. I'm trying to capture that in an enable_if:

template<typename T>
enable_if_t<is_array_v<T> && extent_v<T> == 3U || !is_array_v<T> && tuple_size<T>::value == 3U> foo(const T& param) {}

Unfortunately for an int[3], tupple_size is not defined, which causes the template to fail to compile, before short circuiting is evaluated.

I have also tried to do this using a conditional but that has the same problem of ensuring both options are valid for T before considering the condition.

I know that I can do this by specializing. But the code is the exact same in the body of the function. I hate the fact that I'm specializing when the implementation is the same.

Is there a way I can force the short circuit before evaluating the conditions?

like image 606
Jonathan Mee Avatar asked Dec 07 '22 14:12

Jonathan Mee


1 Answers

Taking advantage of the fact that extent<T> for non-array types is zero and hence falsy, and disjunction derives from the first truthy type in the list with short circuiting:

template<typename T>
enable_if_t<disjunction<extent<T>, tuple_size<T>>::value == 3U> foo(const T& param) {}

This is probably too clever. Note that you can't use disjunction_v here.


conditional should work just fine too. The trick is to not ask for ::value until you've picked the right type:

template<typename T>
enable_if_t<conditional_t<is_array_v<T>, extent<T>, tuple_size<T>>::value == 3U> 
    foo(const T& param) {}
like image 135
T.C. Avatar answered Dec 30 '22 02:12

T.C.