- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我需要编写一个宏来处理任意长的列表,例如 (A)(B)(C)
。如果我可以采用 Boost 依赖项,我将只使用 BOOST_PP_SEQ_
之一宏系列。不幸的是,我不能,所以我只能尝试弄清楚它是如何工作的。这东西并不明显。
这里有人能写一个简单的、独立的实现吗,比方说,BOOST_PP_SEQ_FOLD_LEFT
给我看看?特别是,我想转换:
template_(class A, class B, class C)(
requires IsFoo<A> && IsBar<B>)(
requires IsBaz<C>)
void frobozzle(A, B, C);
重写为:
template<class A, class B, class C,
int dummy = 0,
std::enable_if_t<dummy == 0 && (IsFoo<A> && IsBar<B>), int> = 0,
std::enable_if_t<dummy == 0 && (IsBaz<C>), int> = 0>
void frobozzle(A, B, C);
可以有任意数量的 requires
子句,并且每个子句都应该有自己的 enable_if_t
。我让它与一个 requires
子句一起工作,但我在这个过程中耗尽了我的 C 预处理器功能。
可以假设一个符合标准的预处理器,因为我不需要 MSVC 支持。
最佳答案
如果您在语法中添加一组额外的括号,则可以不受“必需”子句数量的限制,并且使用相对较少的宏:
template_((class A, class B, class C)
(requires IsFoo<A> && IsBar<B>)
(requires IsBaz<C>)
)
void frobozzle(A, B, C);
宏:
#define template_(...) template_impl_ADD_END(template_impl_LIST __VA_ARGS__) >
#define template_impl_ADD_END(...) template_impl_ADD_END2(__VA_ARGS__)
#define template_impl_ADD_END2(...) __VA_ARGS__ ## _END
#define template_impl_LIST(...) template<__VA_ARGS__, int dummy = 0 template_impl_LIST_1
#define template_impl_LIST_1(...) , std::enable_if_t<dummy == 0 && template_impl_REQUIRES(__VA_ARGS__), int> = 0 template_impl_LIST_2
#define template_impl_LIST_2(...) , std::enable_if_t<dummy == 0 && template_impl_REQUIRES(__VA_ARGS__), int> = 0 template_impl_LIST_1
#define template_impl_REQUIRES(...) (template_impl_REQUIRES_ ## __VA_ARGS__)
#define template_impl_REQUIRES_requires
#define template_impl_LIST_END
#define template_impl_LIST_1_END
#define template_impl_LIST_2_END
使用这些宏,上面的示例扩展为:
template <class A, class B, class C,
int dummy = 0,
std::enable_if_t<dummy == 0 && (IsFoo<A> && IsBar<B>), int> = 0,
std::enable_if_t<dummy == 0 && (IsBaz<C>), int> = 0>
void frobozzle(A, B, C);
考虑这些宏:
#define a(x) [x] b
#define b(x) [x] a
有了这些,这个:
a (1) (2) (3) (4)
会引起膨胀的“链式 react ”如下:
a (1) (2) (3) (4)
[1] b (2) (3) (4)
[1] [2] a (3) (4)
[1] [2] [3] b (4)
[1] [2] [3] [4] a
预处理器中不允许递归,但这种类型的链式 react 不是递归,因为宏的调用只发生在前一个扩展之后,而不是在扩展期间,因为 (
不是扩展的一部分。(虽然,请参阅 https://wg21.link/cwg268 )
不幸的是,虽然这会很好地遍历一系列 (A)(B)(C)
,但它会在末尾留下一个额外的标记:所使用的两个标记之一的名称宏。我用来摆脱那个的技巧是用另一个宏调用包装整个列表,它将在完全展开,所以它将变成:
[1] [2] [3] [4] a_END
然后我们可以简单地通过定义去掉最后一个标记:
#define a_END
#define b_END
如果我们不能包装整个列表,就无法知道何时到达最后一个元素。唯一发生的事情是最后一个 a
或 b
没有跟在它后面的 (
,这意味着它根本不会扩展,因为 a
和 b
是函数样式的宏。(而且我们不能只定义 a
和 b
展开为空,因为 a
和 b
已经是宏,尽管它们在没有 (
.)
当我们试图用像上面这样的一个宏引起链式 react 时:
#define a(x) [x] a
它不会工作:
a (1) (2) (3) (4)
[1] a (2) (3) (4) // Doesn't expand further
这是因为“(无限)递归保护”是如何工作的:如果在宏扩展期间,产生了一个带有被扩展宏名称的标记,它被标记为“不可扩展”,这意味着它永远不会再扩大。参见 http://eel.is/c++draft/cpp.rescan#2
这意味着扩展的 a
被标记为“不可扩展”,我们的链式 react 在第一步之后就停止了。我们通过使用两个宏来解决此规则来避免这种情况:a(..)
不会生成任何具有自己名称的标记,而只会生成另一个宏 b
。
a
的扩展就在那里结束,在 b
被扩展之前,因为在 b 之后还没有 (
,因为我们在“内部” a 的扩展。扩展完成后,我们不再“内部”a
,重新检查标记,正确调用 b
是找到:b(..)
。那个将再次生成一个名为 a
的标记,但是因为我们不再处于第一个 的扩展中>a
,这个不会被标记为'unexpandable',链式 react 继续。
关于c++ - BOOST_PP_SEQ_FOLD_LEFT 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48307385/
我需要编写一个宏来处理任意长的列表,例如 (A)(B)(C)。如果我可以采用 Boost 依赖项,我将只使用 BOOST_PP_SEQ_ 之一宏系列。不幸的是,我不能,所以我只能尝试弄清楚它是如何工作
我是一名优秀的程序员,十分优秀!