You've already received good template based solutions. I had authored one myself, but it duplicated another answer. So, this answer is different, but it also does not use templates. Instead, it uses a variadic macro.
If you need true short-circuit behavior, then you will need to expand out the full expression. Otherwise, if the parameters have side-effects, passing them into a function will trigger all of them. As a contrived example,
template <typename T>
const T & x(const T &v) {
std::cout << __func__ << ": " << v << '\n';
return v;
}
//...
if (is_any_of(2, x(1), x(2), x(3))) {
//...
}
A short-circuit implementation would avoid calling x(3)
when the match is detected on the x(2)
. But, that would require that is_any_if(...)
expand to:
if ((2 == x(1)) || (2 == x(2)) || (2 == x(3))) {
//...
You can use a macro to accomplish this expansion. Below is one possible implementation, which can take up to 9 parameters to test against.
#define is_any_of(...) \
(V_(V_(is_any_of_X(__VA_ARGS__,A,9,8,7,6,5,4,3,2,_))(__VA_ARGS__)))
#define is_any_of_X(_A,_9,_8,_7,_6,_5,_4,_3,_2,_1,X,...) is_any_of_##X
#define is_any_of_A(V, X, ...) ((X) == (V)) || is_any_of_9(V, __VA_ARGS__)
#define is_any_of_9(V, X, ...) ((X) == (V)) || is_any_of_8(V, __VA_ARGS__)
#define is_any_of_8(V, X, ...) ((X) == (V)) || is_any_of_7(V, __VA_ARGS__)
#define is_any_of_7(V, X, ...) ((X) == (V)) || is_any_of_6(V, __VA_ARGS__)
#define is_any_of_6(V, X, ...) ((X) == (V)) || is_any_of_5(V, __VA_ARGS__)
#define is_any_of_5(V, X, ...) ((X) == (V)) || is_any_of_4(V, __VA_ARGS__)
#define is_any_of_4(V, X, ...) ((X) == (V)) || is_any_of_3(V, __VA_ARGS__)
#define is_any_of_3(V, X, ...) ((X) == (V)) || is_any_of_2(V, __VA_ARGS__)
#define is_any_of_2(V, X) ((X) == (V))
#define is_any_of_1(...) false
#define is_any_of_0(...) true
#define is_any_of_Y(_1,Y,...) is_any_of_##Y
#define is_any_of__(...) I_(is_any_of_Y, E_ __VA_ARGS__ () 0, 1)(__VA_ARGS__)
#define V_(...) __VA_ARGS__
#define I_(M,...) V_(M(__VA_ARGS__))
#define E_() _,
The technique is explained here. Briefly, it applies a macro argument counting trick, as well as a portable method to detect whether the single argument case is actually the empty argument case. (If you are using GCC, the detection can be simplified.)