C++ C++;用于指定多个条件的可变宏
我怀疑我做不到这一点,但我想我应该先问问这里的智者社区 我想检查少数变量(比如10个,虽然可能只有两三个)是否等于相同的特定值。e、 gC++ 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语句。可以为多
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))