C ++ Variadic宏指定多个条件

时间:2011-03-17 04:26:29

标签: c++ c macros

我怀疑我不能这样做,但我想先在这里问明智社区。

我想检查一小撮(比如十个,但可能只有两三个)变量是否等于相同的特定值。 e.g。

if (X == 3 || Y == 3 || Z == 3 || W == 3) ...

在Python中,我习惯于简单地做if 3 in (X, Y, Z, W):,但无论如何。

无论如何,我想知道是否有可能将它抽象为变量宏,例如EQU_ANY(3, X, Y, Z, W),而不是编写一堆EQU_ANYX宏,其中X是args的数量。

4 个答案:

答案 0 :(得分:4)

[使用宏的解决方案结束了,因为它相当可怕而且令人讨厌。]


如果你不介意制作副本,使用std::find

可能更干净
std::array<int, 4> values = { X, Y, Z, W };
if (std::find(values.begin(), values.end(), 3) != values.end()) { }

将这一行包装成一个函数通常很好:

template <typename Container, typename Value>
bool contains(const Container& c, const Value& v) 
{
    return std::find(c.begin(), c.end(), v) != c.end();
}

用作:

std::array<int, 4> values = { X, Y, Z, W };
if (contains(values, 3)) { }

在C ++ 0x中,您可以使用初始化列表而不是创建临时数组:

if (contains({ X, Y, Z, W }, 3)) { }

(这适用于gcc 4.5+;我还不知道还有其他任何支持此C ++ 0x功能的编译器。)


如果你真的想避免复制对象(例如,如果它们很大或复制成本很高),你可以使用相同功能的间接版本:

#include <boost/iterator/indirect_iterator.hpp>

template <typename Container, typename Value>
bool indirect_contains(const Container& c, const Value& v)
{
    return std::find(boost::make_indirect_iterator(c.begin()),
                     boost::make_indirect_iterator(c.end()),
                     v) 
        != boost::make_indirect_iterator(c.end());
}

用作:

std::array<int*, 4> values = { &X, &Y, &Z, &W };
if (indirect_contains(values, 3)) { }

或者,使用C ++ 0x初始化列表:

if (indirect_contains({ &X, &Y, &Z, &W }, 3)) { }

由于Jonathan Leffler提到了Boost.Preprocessor,这就是解决方案的样子:

#include <boost/preprocessor.hpp>

#define SEQUENCE_CONTAINS_IMPL(r, data, i, elem)                          \
    BOOST_PP_IIF(BOOST_PP_EQUAL(i, 0), BOOST_PP_EMPTY(), ||)              \
    ((elem) == (data))


#define SEQUENCE_CONTAINS(elements, value)                                \
    (BOOST_PP_SEQ_FOR_EACH_I(SEQUENCE_CONTAINS_IMPL, value, elements))

用作:

if (SEQUENCE_CONTAINS((X)(Y)(Z)(W), 3)) { }

扩展为:

if ((((X) == (3)) || 
     ((Y) == (3)) || 
     ((Z) == (3)) || 
     ((W) == (3)))) { }

(这很丑陋而且很可怕;我不会在我的代码中使用它,但是如果你真的担心要制作两三个值的副本,你可能不希望有机会进行函数调用无论是。)

答案 1 :(得分:1)

尝试使用switch语句。您可以为多个条件指定相同的行为,如下所示:

switch (n) {
    case 1:
    case 2:
    case 3:
        // Do something
        break;
}

这相当于

if (x == 1 || x == 2 || x == 3)
    // Do something

这是最干净的方法。你或许可以编写一个可变开关宏(或者能完成类似事情的东西),但请为你身边的每个人做...不要:P

答案 2 :(得分:1)

由于您还使用C标记了您的问题,因此这是一个仅适用于C99和可变参数宏的答案,C ++没有。使用P99执行语句展开

#define TESTIT(WHAT, X, I) X == WHAT
#define TEST_MORE(WHAT, ...) P99_FOR(WHAT, P99_NARG(__VA_ARGS__), P00_OR, TESTIT, __VA_ARGS__)

这里

TEST_MORE(A, b, c, d, e, f)
TEST_MORE(3, b, c, d, e, f)

然后

((((((((b == A) || (c == A))) || (d == A))) || (e == A))) || (f == A))
((((((((b == 3) || (c == 3))) || (d == 3))) || (e == 3))) || (f == 3))

与boost相比,这样做的优势在于对TEST_MORE的最终调用简单易读。

答案 3 :(得分:0)

最有可能使用Boost的boost::preprocessor包中的工具(可以与C和C ++一起使用)来完成。