C++ C++;用于指定多个条件的可变宏

C++ C++;用于指定多个条件的可变宏,c++,c,macros,C++,C,Macros,我怀疑我做不到这一点,但我想我应该先问问这里的智者社区 我想检查少数变量(比如10个,虽然可能只有两三个)是否等于相同的特定值。e、 g if (X == 3 || Y == 3 || Z == 3 || W == 3) ... 在Python中,我习惯于简单地执行if 3 In(X,Y,Z,W):,但不管怎样 无论如何,我想知道是否有可能将其抽象为一个可变宏,例如equalany(3,X,Y,Z,W),而不是编写一堆equalanyx宏,其中X是参数的数量。尝试使用switch语句。可以为多

我怀疑我做不到这一点,但我想我应该先问问这里的智者社区

我想检查少数变量(比如10个,虽然可能只有两三个)是否等于相同的特定值。e、 g

if (X == 3 || Y == 3 || Z == 3 || W == 3) ...
在Python中,我习惯于简单地执行
if 3 In(X,Y,Z,W):
,但不管怎样


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

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

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

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

这是最干净的方法。您可能可以编写一个可变开关宏(或完成类似操作的东西),但请为您周围的每个人。。。不要:P

这很可能可以使用Boost软件包中的工具(可以与C和C++一起使用)来完成。

[使用宏的解决方案已经到了最后,因为它非常可怕和恶心。]


如果您不介意复制,那么使用
std::find
:

std::array<int, 4> values = { X, Y, Z, W };
if (std::find(values.begin(), values.end(), 3) != values.end()) { }
(这在GCC4.5+中有效;我还不知道有任何其他编译器支持此C++0x特性。)


如果确实希望避免复制对象(例如,如果复制对象太大或成本太高),可以使用相同功能的间接版本:

template <typename Container, typename Value>
bool contains(const Container& c, const Value& v) 
{
    return std::find(c.begin(), c.end(), v) != c.end();
}
#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());
}

由于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 ((((X) == (3)) || 
     ((Y) == (3)) || 
     ((Z) == (3)) || 
     ((W) == (3)))) { }

(这是丑陋和可怕的,我不会在我的代码中使用这个,但是如果你真的担心两个或三个值的拷贝,你可能不想碰上一个函数调用。)

,因为你也用C来标记你的问题,这是一个只适用于C99和变量宏的答案,C++没有。用于执行语句展开

#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\u MORE
的最终调用简单易读

不,宏是错误的工具--在宏中无法迭代参数。谢谢Jim,这就是我想知道的。(啊,要是我有Lisp宏就好了。)好吧,结果证明我错了——boost::preprocessor包有很多方法可以实现多达256个参数。看看Jonathan和James的答案(你真的应该接受后者)。这很有效,直到我想使用Int或chars之外的东西。尽管如此,我还是想要一个宏,因为使用switch会导致更多的类型(甚至比条件类型!),而不是更少,而且我敢打赌编译器足够聪明,可以将这些琐碎的条件优化为switch/goto。编辑等待,你的方式让我更困惑…@Kevin有几个条件是可以的,但当你得到5个或更多,最好写开关。使用
==
测试相等性不适用于字符串或浮点,IIRC,因此您的条件也不适用于字符串或浮点。不要担心你输入了多少,差别很小。担心可读性。无法编写可变开关宏,因为无法引用单个可变参数。预处理器的功能非常有限。我仍然认为没有开关它更可读。它不在Python中是有原因的。。。因此,“可读性”在这里是个人偏好。无论如何,我的困惑在于开关(3){case X:case Y:}是合法的,我以前从未见过。@Kevin“我敢打赌编译器足够聪明,可以将这些琐碎的条件优化为开关/转到”--打赌编译器不能做众所周知的事情是不明智的。预处理器只允许将变量宏参数作为一个组引用(
\uuu VA\u ARGS\uu
),而boost::preprocessor或任何其他包都无法改变这一点--如果您想迭代参数,你必须用C/C++代码来做。@Jim:我不同意。我已经发布了一个使用预处理器的示例。做这类事情非常简单,尤其是当使用Boost.Preprocessor来完成所有繁重的工作时。@James是的,我收回了!虽然对于任意变量参数列表是正确的,但是boost通过为每个参数数定义一个单独的宏来处理多达256个参数,并且如果有n个参数,宏将返回true,否则返回false。我仍在试图理解代码,但它相当曲折(而且庞大)。回复:谢谢你的编辑!我可能不会使用它,我同意它很难看,但它仍然非常棒。Boost可以做到这一点。@Kevin不管拷贝是否邪恶,James使用Boost::preprocessor给出的解决方案满足您最初的请求,与拷贝无关。@Jim Balter是的,因此我接受它作为解决方案。现在使用它唯一值得商榷的问题是它有点丑陋(没那么糟糕),更重要的是,它引入了预处理器所需的任何Boost依赖项。复制解决方案的好处在于它是标准的(不管怎样,对于gcc来说)。Boost.Preprocessor库不应该有任何依赖项,所以您应该能够使用“Preprocessor”源目录和“Preprocessor.hpp”并使用它们。(我知道,我知道,我说过应该:-D。不过我几乎可以肯定。)此外,它也适用于C代码,因为它纯粹是一个预处理库(C90和C++03具有几乎相同的预处理规范)。我很好奇,
初始值设定项\u list
是否可以引用…@Kevin Boost使用编译器的预处理器;没有依赖关系。只需下载并安装它,然后开始
#包括
ing——没有其他需要做的事情了。
if (SEQUENCE_CONTAINS((X)(Y)(Z)(W), 3)) { }
if ((((X) == (3)) || 
     ((Y) == (3)) || 
     ((Z) == (3)) || 
     ((W) == (3)))) { }
#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))