【问题标题】:Variadic macros可变参数宏
【发布时间】:2011-09-11 08:51:21
【问题描述】:

有没有办法写这样的宏:

#define G(x1, x2, ... , xn) f(x1), f(x2), ... , f(xn)

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

C++0x 答案没问题。

编辑:我问的是如何创建这种形式的宏,而不是通常采用可变数量参数的宏。

目标::所以我可以执行以下操作:

#define MAKE_TUPLE(x1, x2, ... , xn) mytuple<decltype((x1)), decltype((x2)), ... , decltype((xn))>{x1, x2, ... , xn}

所以这个mytuple 可以在没有移动和复制的情况下创建,也不需要对可以使用聚合构造就地创建的临时对象的不必要引用。

【问题讨论】:

  • 如果你使用了 C++0x 的任何特性,那么它就不是宏。
  • @Mehrdad:C++0x 中的宏没有变化吗?如果是这样,我会删除标签。
  • @Clinton: What for? 询问目标,而不是步骤。 (它真的需要是一个宏吗?C C++,而不是两者。)
  • @Clinton:我打算做一个通用的命名参数库——如果你开始引入这样的宏,没有人会使用那个库。

标签: c++ c++11 macros c-preprocessor variadic-macros


【解决方案1】:

目标:[去掉对再次错误方法的描述]。所以这个 mytuple 可以在没有移动和复制的情况下创建,也不需要对可以使用聚合构造就地创建的临时对象的不必要引用。

您在评论中使您的要求更加精确

理想情况下,通过我的参数包传递应该尽可能快地与普通参数传递一样快。我想这些参数包可能会变得相当大。

你走错了路。以下不是宏,不创建移动或副本(不超过宏),并且没有对临时对象的不必要引用(不确定您的要求的最后一部分是什么意思,但我认为我们可以反复澄清)。它和“普通参数传递”一样快,因为它什么都不做。

template<typename ...T>
mytuple<T...> make_tuple(T&&... t) {
  return mytuple<T...>{std::forward<T>(t)...};
}

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

  • prvalues 以X 的形式转发到元组
  • Xvalues 作为X 转发到元组
  • 左值作为X&amp; 转发到元组

你的宏表现不同

  • prvalues 以X 的形式转发到元组
  • Xvalues 作为X&amp;&amp; 转发到元组
  • 左值作为X&amp; 转发到元组

注意中间部分——你很容易出现悬空引用,除非你的元组的生命周期总是小于所有参数的生命周期,但是将prvalues存储为X会创建一个不必要的副本。在我的代码中使用mytuple&lt;T&amp;&amp;...&gt; 始终使用引用,如下

  • prvalues 以X&amp;&amp; 的形式转发到元组
  • Xvalues 作为X&amp;&amp; 转发到元组
  • 左值作为X&amp; 转发到元组

【讨论】:

    【解决方案2】:

    如果你愿意使用稍微笨拙的语法,那么你可以使用 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)
    

    用法:

    G((a))
    G((b)(c))
    G((d)(e)(f))
    

    结果:

    f(a)
    f(b) , f(c)
    f(d) , f(e) , f(f)
    

    如果您确实需要 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__)    
    

    用法:

    G(a)
    G(b, c)
    G(d, e, f)
    

    结果:

    f(a)
    f(b), f(c)
    f(d), f(e), f(f)
    

    这当然可以进一步推广,一些预处理器实用程序库可能已经有一些工具可以做到这一点,但这展示了如何做到这一点。 (我不熟悉任何 C99/C++0x 预处理器库,所以我不能推荐。)

    【讨论】:

      【解决方案3】:

      我记得 Boost Preprocessor 库可以做到这一点,即使对于 C++98。

      但是,宏是邪恶的,最好避免使用。

      考虑做类似的事情

      Type const values[] = {x1, x2, x3, ... xn};
      
      for( int i = 0;  i < countOf( values );  ++i )
      {
          f( values[i] );
      }
      

      干杯&hth。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-13
        • 1970-01-01
        • 1970-01-01
        • 2013-05-21
        • 2011-08-18
        • 1970-01-01
        • 1970-01-01
        • 2014-12-22
        相关资源
        最近更新 更多