变体宏

Cli*_*ton 3 c++ macros c-preprocessor variadic-macros c++11

有没有办法写这样的宏:

#define G(x1, x2, ... , xn) f(x1), f(x2), ... , f(xn)
Run Code Online (Sandbox Code Playgroud)

或者我需要为每个人定义这个n吗?

C++ 0x答案还可以.

编辑:我问的是如何创建这个表单的宏,而不是一般采用可变数量的参数的宏.

目标:所以我可以做以下事情:

#define MAKE_TUPLE(x1, x2, ... , xn) mytuple<decltype((x1)), decltype((x2)), ... , decltype((xn))>{x1, x2, ... , xn}
Run Code Online (Sandbox Code Playgroud)

因此,这mytuple可以在没有移动和复制的情况下创建,也可以使用聚合构造在临时创建的临时工具中进行不必要的引用.

Jam*_*lis 5

如果您愿意使用稍微笨拙的语法,那么您可以使用Boost.Preprocessor的序列:

#include <boost/preprocessor.hpp>

#define G(args) BOOST_PP_SEQ_FOR_EACH_I(G_GENF, x, args)
#define G_GENF(r, data, i, elem) \
    BOOST_PP_COMMA_IF(BOOST_PP_NOT_EQUAL(i, 0)) f(elem)
Run Code Online (Sandbox Code Playgroud)

用法:

G((a))
G((b)(c))
G((d)(e)(f))
Run Code Online (Sandbox Code Playgroud)

结果:

f(a)
f(b) , f(c)
f(d) , f(e) , f(f)
Run Code Online (Sandbox Code Playgroud)

如果你确实需要G(a, b, c)语法,那么因为宏替换不是递归的,我认为你可能需要为每个参数提供一个宏.但是,您仍然可以从源中其他位置使用的单个宏委派这些宏.考虑:

// Utility for counting the number of args in the __VA_ARGS__ pack:
#define PP_NARGS(...) PP_NARGS2(__VA_ARGS__, PP_NARGS_COUNT())
#define PP_NARGS2(...) PP_NARGS_IMPL(__VA_ARGS__)
#define PP_NARGS_IMPL(x1, x2, x3, N, ...) N
#define PP_NARGS_COUNT() 3, 2, 1, 0, ERROR

// Macros to delegate to concrete, defined-arity implementations:
#define XF(count, ...) XF_IMPL (count, __VA_ARGS__)
#define XF_IMPL(count, ...) XF_ ## count (__VA_ARGS__)

// Defined-arity implementations:
#define XF_1(x1)         f(x1)
#define XF_2(x1, x2)     f(x1), f(x2)
#define XF_3(x1, x2, x3) f(x1), f(x2), f(x3)

// Delegation macro; this is the only macro you need to call from elsewhere:
#define G(...) XF(PP_NARGS(__VA_ARGS__), __VA_ARGS__)    
Run Code Online (Sandbox Code Playgroud)

用法:

G(a)
G(b, c)
G(d, e, f)
Run Code Online (Sandbox Code Playgroud)

结果:

f(a)
f(b), f(c)
f(d), f(e), f(f)
Run Code Online (Sandbox Code Playgroud)

这当然可以进一步推广,并且一些预处理器实用程序库可能已经有了一些工具来实现这一点,但这证明了它是如何完成的.(我不熟悉任何C99/C++ 0x预处理器库,所以我不推荐一个.)


Joh*_*itb 5

目标:[删除了对错误方法的描述].因此,这个mytuple可以在没有移动和复制的情况下创建,也可以创建不必要的临时工具,这些临时工具可以使用聚合构造在适当的位置创建.

您在评论中更加精确地满足了您的要求

理想情况下,通过我的参数包传递应尽可能接近普通参数传递的速度.我想这些参数包可能会变得相当大.

你走错了路.以下不是宏,不创建任何移动或副本(不超过宏)并且没有对临时工具的不必要的引用(不确定您的要求的最后部分意味着什么,但我认为我们可以迭代地澄清).它和"普通的论证传递"一样快,因为它什么也没做.

template<typename ...T>
mytuple<T...> make_tuple(T&&... t) {
  return mytuple<T...>{std::forward<T>(t)...};
}
Run Code Online (Sandbox Code Playgroud)

decltype对于参数类型,这与您给出的表达式序列有不同的行为X

  • Prvalues被转发到元组,如 X
  • Xvalues被转发给元组as X
  • 左值被转发给元组 X&

你的宏表现不同

  • Prvalues被转发到元组,如 X
  • Xvalues被转发给元组as X&&
  • 左值被转发给元组 X&

注意中间部分 - 您倾向于悬挂引用,除非您的元组的生命周期始终小于所有参数的生命周期,但随后存储prvalues X会创建不必要的副本.用mytuple<T&&...>在我的代码总是使用引用,如下

  • Prvalues被转发到元组,如 X&&
  • Xvalues被转发给元组as X&&
  • 左值被转发给元组 X&