Home > OS >  Variadic macro for checking if variable equals one of variadic arguments
Variadic macro for checking if variable equals one of variadic arguments

Time:10-20

I'm currently working on a WebGL-like OpenGL wrapper in (Image of a naive conditional (possible internalformat constants for glTexImage2D, if you're interested. I literally wrote a JS table parser/conditional maker for a few of those) to make my point. That's an assert...)

The logic of such checks is simple enough:

bool check(const unsigned int var)
{
    return var == CONSTANT_1 || var == CONSTANT_2 || var == CONSTANT_...;
}

But, as per the above example, this can stretch for up to 84 possible constants, which is... yeah. And I'm fully aware that a macro wouldn't cut this down by an absurd amount, but it would still make a difference, and I feel like it would be cleaner too. Not to mention the possibility of other macros of a similar fashion with different operators.

So my idea was to use a macro. After all, this check would be trivial to do at runtime, with a std::initializer_list``, std::vector, std::array` or some other container, but since all of these constants are known at compile time, I feel as though this is unnecessary.

Since the number of possible constants is variable, I see no way of not using a variadic macro. Yet I don't know how I would accomplish this. One possible way I thought of doing this is basically overloading a macro based on the number of arguments (akin to this), but this seems unnecessarily complex.

In essence, I'm looking for a macro that would fulfill the following:

MACRO(var, CONSTANT_1, CONSTANT_2, CONSTANT_3)

expands to

var == CONSTANT_1 || var == CONSTANT_2 || var == CONSTANT_3

with any number of constants (important!, and the hard part).

CodePudding user response:

You might want to use C 17 fold expression:

template<class... Args>
bool check(const unsigned int var, const Args&... args)
{
  return ((var == args) || ...);
}

Then you can invoke something like this:

check(var, CONSTANT_1, CONSTANT_2, CONSTANT_3);

CodePudding user response:

You do not need the macros. If you have the constants in a constexpr std::array, you can make use of std::any_of as follows:

#include <algorithm>  // std::any_of

inline static constexpr std::array<unsigned int, 2> arr_of_const{ CONSTANT_1, CONSTANT_2 };

consteval bool check(unsigned int var)
{
    return std::any_of(arr_of_const.cbegin(), arr_of_const.cend(), [var](auto ele) { return var == ele; });
}

CodePudding user response:

No need to use macros here, a simple function and array of valid values will do the job:

#include <array>
#include <algorithm>
#include <iostream>

constexpr int CONSTANT_1 = 0;
constexpr int CONSTANT_2 = 1;
constexpr int CONSTANT_3 = 2;
constexpr int CONSTANT_4 = 3;

constexpr std::array<int, 3 > VALID_CONSTANTS = { CONSTANT_1, CONSTANT_2, CONSTANT_3 };

template <size_t N>
constexpr bool check(int value, const std::array<int, N>& values)
{
    return std::find(values.begin(), values.end(), value) != values.end();
}

int main()
{
    std::cout << check(CONSTANT_1, VALID_CONSTANTS) << "\n";
    std::cout << check(CONSTANT_4, VALID_CONSTANTS) << "\n";
}

With a small modification the code is completely evaluated at compile time:

#include <array>
#include <algorithm>
#include <iostream>

constexpr int CONSTANT_1 = 0;
constexpr int CONSTANT_2 = 1;
constexpr int CONSTANT_3 = 2;
constexpr int CONSTANT_4 = 3;

struct VALID_CONSTANTS
{
    static constexpr std::array<int, 3 > values = { CONSTANT_1, CONSTANT_2, CONSTANT_3 };
};

template <typename Values>
constexpr bool check(int value)
{
    return std::find(Values::values.begin(), Values::values.end(), value) != Values::values.end();
}

int main()
{
    std::cout << check<VALID_CONSTANTS>(CONSTANT_1) << "\n";
    std::cout << check<VALID_CONSTANTS>(CONSTANT_4) << "\n";
}
  • Related