【问题标题】:How to implement Matt Calabrese's BOOST_AUTO_FUNCTION idea?如何实现 Matt Calabrese 的 BOOST_AUTO_FUNCTION 理念?
【发布时间】:2022-06-16 06:00:38
【问题描述】:

a talk from BoostCon 2011 中,Matt Calabrese 给出了以下假设语法:

template< class L, class R >
BOOST_AUTO_FUNCTION( operator -( L const& lhs, R const& rhs )
                   , if ( is_vector_udt< L > )
                        ( is_vector_udt< R > )
                   , try ( lhs + rhs )
                         ( -rhs )
                   , if typename ( L::value_type )
                   )
(
  return lhs + -rhs
)

这个想法是声明一个函数模板:

  1. 命名为operator-
  2. 带有参数L const&amp; lhsR const&amp; rhs
  3. 除非is_vector_udt&lt;L&gt;is_vector_udt&lt;R&gt; 为真,否则不参与重载解决,
  4. 除非lhs + rhs-rhs 是有效表达式,否则不参与重载决议,
  5. 不参与重载决议,除非L::value_type 是有效类型,
  6. 他的身体是return lhs + -rhs;,并且
  7. 从给定的正文推导出返回类型;

在没有实际语言级概念的情况下使用类似概念的语法(它应该在我们得到的 C++11 中工作,而不是我们想要的)。

我对上面列表中的第 3、4 和 5 点最感兴趣。建议的语法重新使用通常是关键字的单词。例如,这里的try 显然不是指异常处理,但是宏必须将try(lhs+rhs)(-rhs) 转换为可以参与SFINAE 的东西,例如sizeof((void)(lhs+rhs),(void)(-rhs),0),但前提是它发生在@ 的调用中987654337@ 宏。我不熟悉高级预处理技术,所以我不知道如何做到这一点。

或者我误解了,Calabrese 实际上并没有声称这种语法是可实现的(尽管这很奇怪;我认为他会选择展示一些可实现的语法)。

【问题讨论】:

  • 一目了然,我假设宏正在使用串联来添加某些内容,例如,try 变为 BOOST_AUTO_FUNCTION_ARG_try,这将被预定义为函数宏。不过,if typename 的案例非常有趣。
  • 没有太多关于此的信息,但有一个Boost discussion。虽然似乎没有可用于他的最终实现的代码,但与end of that thread 的相似之处更多。他确实说过双词 ID 不能使用与单词 ID 相同的第一个词。所以他找到了一些黑魔法来解决这个问题,或者幻灯片可能有错误。让他记住十年前的努力可能是您对if typename 的最佳选择。

标签: c++ macros


【解决方案1】:

如果我理解正确,您希望根据特定条件让函数参与重载列表。您可以使用多种结构来实现目标。我们将使用 std::enable_if_t,它利用了 C++ 的 SFINAE 属性。

您可以找到std::enable_if_t here 的文档。

以下解决方案针对 C++11 及更高版本。

首先,我们将创建一个向量类型,其中包含您想要的运算符和一个特征来检查一个类型是否与我们的向量的类型匹配。下面是一个声明和测试它的小代码示例。

#include <iostream>
#include <type_traits>
#include <vector>
#include <cassert>

template<typename V>
struct My_vector
{
    My_vector(std::vector<V> const &init) : v_(init) {}
    My_vector(std::initializer_list<V> const &init) : v_(init) {}

    My_vector operator-()
    {
        std::vector<V> res(v_);
        for (auto & a : res)
            a = -a;
        return res;
    }
    template<typename U>
    My_vector operator+(My_vector<U> const & rhs)
    {
        assert (rhs.v_.size() ==  v_.size());
        std::vector<V> res(v_);
        for(auto l = res.begin(), r = rhs.v_.begin(); l != res.end(); l++, r++)
            *l = *l + *r;
        return res;
    }
    
    std::vector<V> v_;
};
template<typename T>
struct is_my_vector : std::false_type {};

template<typename T>
struct is_my_vector<My_vector<T>> : std::true_type {};

int main(int argc, char const* argv[])
{
    My_vector<int> v1 {1, 2, 3};
    My_vector<double> v2 {4, 5, 6};
    
    auto v3 = v1 + v2;
    auto v4 = -v2;
    
    std::cout << std::boolalpha;
    std::cout << is_my_vector<std::vector<int>>::value << std::endl;
    std::cout << is_my_vector<decltype(v1)>::value << std::endl;
    std::cout << is_my_vector<decltype(v2)>::value << std::endl;
    std::cout << is_my_vector<decltype(v3)>::value << std::endl;
    std::cout << is_my_vector<decltype(v4)>::value << std::endl;

    return 0;   
}

现在我们可以像这样声明我们的- 运算符:

template<
    typename L, 
    typename R, 
    typename = std::enable_if_t<is_my_vector<L>::value, L*>,
    typename = std::enable_if_t<is_my_vector<R>::value, R*>
>
auto operator-(L const & lhs, R const & rhs) -> decltype(lhs + -rhs)
{
    return lhs + -rhs;
}

使用std::enable_if_t 以这种方式声明它将确保仅当LR 属于My_vector&lt;T&gt; 时才会考虑该函数。

请注意,decltype 中的表达式是在编译时计算的,并且没有运行时开销。我认为从 C++14 开始,您可以完全省略 return decltype。

要对此进行测试,只需创建一个具有 operator-operator+ 的类型,就像我们为 My_vector 所做的那样,并尝试从另一个实例中构造一个实例 = 编译将失败。但是,如果您从模板定义中删除 typename = std::enable_if_t 行,您将看到您的代码编译正常。

这可能不是你想要的 100%,因为我们没有以 SFINAE 的方式检查 -+ 运算符的存在,但是因为我们知道我们的类型有这些运算符,所以没有必要

【讨论】:

    【解决方案2】:

    tl;博士:

    • 因为它是 BOOST_AUTO_FUNCTION 在 C++11 中无法实现

      • SFINAE 部件可以正常工作
      • 由于未计算的上下文中不允许使用 lambda,因此不可能从任意语句中推导返回类型
    • BOOST_AUTO_FUNCTION 的略微修改版本是可能的,它不会从表达式中推断出返回类型,而是从另一个参数中推断出来。
      例如:

      template< class L, class R >
      BOOST_AUTO_FUNCTION( operator -( L const& lhs, R const& rhs ),
                         lhs + -rhs // <- this will be used to deduce the return type
                       , if ( is_vector_udt< L > )
                            ( is_vector_udt< R > )
                       , try ( lhs + rhs )
                             ( -rhs )
                       , if typename ( L::value_type )
                       )
      (
        return lhs + -rhs
      )
      
    • 这是修改后的BOOST_AUTO_FUNCTION 的完整实现:​​

    本文的其余部分将详细介绍如何在 C++11 中使用没有任何库的宏构建 BOOST_AUTO_FUNCTION


    1。解析条件

    让我们首先从一个宏开始,它可以解析来自BOOST_AUTO_FUNCTION 宏的单个条件列表(例如,if (A)(B)(C) / try (A)(B) 成我们可以在 C++ 中使用的东西。

    这样做的基础是 - 正如 @chris 在 cmets 中提到的 - concatenation。通过添加一个固定标记,我们可以将if / try 转换为宏名称以进行进一步处理。

    这样的PARSE_COND 宏可能如下所示:

    #define CONCAT_IMPL(a, b) a ## b
    #define CONCAT(a,b) CONCAT_IMPL(a, b)
    
    #define COND_if    <-IF->
    #define COND_try   <-TRY->
    
    #define PARSE_COND(expr) CONCAT(COND_,expr)
    

    这已经允许我们用我们想要的任何东西替换前面的 if / try

    宏扩展示例:godbolt

    PARSE_COND(if (A)(B))              =>      <-IF-> (A)(B)
    PARSE_COND(try (A)(B))             =>      <-TRY-> (A)(B)
    PARSE_COND(if typename (A)(B))     =>      <-IF-> typename (A)(B)
    

    我们可以使用此技术将if / try 替换为调用另一组宏 (HANDLE_IF / HANDLE_TRY),这些宏将处理下一阶段的处理:godbolt

    #define COND_if    HANDLE_IF (
    #define COND_try   HANDLE_TRY (
    
    #define HANDLE_IF(expr) DOIF: expr
    #define HANDLE_TRY(expr) DOTRY: expr 
    
    #define PARSE_COND(expr) CONCAT(COND_,expr))
    
    PARSE_COND(if (A)(B))              =>      DOIF: (A)(B)
    PARSE_COND(try (A)(B))             =>      DOTRY: (A)(B)
    PARSE_COND(if typename (A)(B))     =>      DOIF: typename (A)(B)
    

    1.1 处理多令牌标识符,如if typename

    现在我们需要处理区分普通的ifif typename
    不幸的是,我们不能使用与if / try 相同的方法,因为连接需要产生一个有效的预处理器令牌 - 并且将某些内容连接到左括号总是会产生一个无效的令牌 => 我们会得到一个预处理器错误。

    例如像这样的东西对于if typename 可以正常工作,但只使用if 会导致错误:godbolt

    #define COND_IF_typename HANDLE_IF_TYPENAME ( 
    #define COND_IF_(...) HANDLE_IF_IF ( (__VA_ARGS__)
    
    #define HANDLE_IF(expr) CONCAT(COND_IF_, expr))
    
    #define HANDLE_IF_TYPENAME(expr) DOIFTYPENAME: expr
    #define HANDLE_IF_IF(expr) DOIF: expr
    
    PARSE_COND(if typename (A)(B))     =>      DOIFTYPENAME: (A)(B)
    PARSE_COND(if (A)(B))              =>      <compiler error>
    

    所以我们需要一种方法来检测是否还有更多的标记需要解析(例如typename),或者我们是否已经达到括号中的条件。

    为此,我们将不得不使用一些宏恶作剧 - 实际上可以通过使用类似函数的宏来检查表达式是否以括号开头。

    如果类函数宏的名称后跟括号,它将展开,否则宏的名称将保持不变。

    示例:godbolt

    #define CHECK(...) EXPANDED!
    #define EXPANSION_CHECK(expr) CHECK expr
    
    EXPANSION_CHECK((A)(B))              =>      EXPANDED!(B)
    EXPANSION_CHECK(typename (A)(B))     =>      CHECK typename (A)(B)
    

    通过使用类函数宏的这个属性,我们可以编写一个可以检测给定表达式中是否有更多标记的宏:godbolt

    #define EXPAND(...) __VA_ARGS__
    #define EMPTY()
    #define DEFER(id) id EMPTY()
    
    #define HAS_MORE_TOKENS(expr) EXPAND(DEFER(HAS_MORE_TOKENS_RESULT)(HAS_MORE_TOKENS_CHECK expr, 0, 1))
    #define HAS_MORE_TOKENS_CHECK(...) ~,~
    #define HAS_MORE_TOKENS_RESULT(a, b, c, ...) c
    
    HAS_MORE_TOKENS(typename (A)(B))     =>      1
    HAS_MORE_TOKENS((A)(B))              =>      0
    

    使用它,我们现在可以处理任何标记序列 - 如果有更多标记,我们可以使用CONCAT()-trick 来进一步扩展它们,如果我们已经达到括号中的条件,我们可以停止并知道哪个序列我们以前读过的令牌。

    示例:godbolt

    #define CONCAT_IMPL(a, b) a ## b
    #define CONCAT(a,b) CONCAT_IMPL(a, b)
    
    #define EXPAND(...) __VA_ARGS__
    #define EMPTY()
    #define DEFER(id) id EMPTY()
    
    #define HAS_MORE_TOKENS(expr) EXPAND(DEFER(HAS_MORE_TOKENS_RESULT)(HAS_MORE_TOKENS_CHECK expr, 0, 1))
    #define HAS_MORE_TOKENS_CHECK(...) ~,~
    #define HAS_MORE_TOKENS_RESULT(a, b, c, ...) c
    
    #define IIF(condition, a, b) CONCAT(IIF_, condition)(a, b)
    #define IIF_0(a, b) b
    #define IIF_1(a, b) a
    
    #define COND_if    HANDLE_IF (
    #define COND_try   HANDLE_TRY (
    
    #define COND_IF_typename HANDLE_IF_TYPENAME (
    
    #define HANDLE_IF(expr) IIF(HAS_MORE_TOKENS(expr), HANDLE_IF_MORE, HANDLE_IF_IF)(expr)
    #define HANDLE_IF_MORE(expr) CONCAT(COND_IF_,expr))
    
    #define HANDLE_IF_TYPENAME(expr) DOIFTYPENAME: expr
    #define HANDLE_IF_IF(expr) DOIF: expr
    #define HANDLE_TRY(expr) DOTRY: expr 
    
    #define PARSE_COND(expr) CONCAT(COND_,expr))
    
    PARSE_COND(if (A)(B))              =>      DOIF: (A)(B)
    PARSE_COND(try (A)(B))             =>      DOTRY: (A)(B)
    PARSE_COND(if typename (A)(B))     =>      DOIFTYPENAME: (A)(B)
    
    1.2 构建 SFINAE 表达式

    接下来,我们需要将实际表达式转换为有效的 C++ SFINAE 代码,以进行 3 种不同类型的检查。

    我们将检查注入返回类型,例如:

    template<class L, class R>
    auto operator+(L const&, R const&) -> decltype(<check A>, <check B>, <actual deduced return type>) {
      /* ... */
    }
    
    • 对于if,我们可以使用std::enable_if:
      expr -> typename std::enable_if&lt;expr::value&gt;::type()
      如果expr 为真,这将导致void(),如果expr 为假,则产生替换错误
    • 对于try,我们可以保持表达式不变。
    • 对于if typename,我们可以使用std::declval:
      expr -> std::declval&lt;typename expr&gt;()
      我们需要使用std::declval,因为expr 可能不是默认可构造的。

    因此,我们现在可以通过一个小的 foreach 宏将所有 3 种类型的 SFINAE 条件转换为 C++ 代码:godbolt

    #define SEQ_HEAD(seq) EXPAND(DEFER(SEQ_HEAD_IMPL)(SEQ_HEAD_EL seq))
    #define SEQ_HEAD_EL(el) el,
    #define SEQ_HEAD_IMPL(head, tail) head
    #define SEQ_TAIL(seq) SEQ_TAIL_IMPL seq
    #define SEQ_TAIL_IMPL(el)
    
    #define FOR_EACH(func, seq) IIF(HAS_MORE_TOKENS(seq), FOR_EACH_END, FOR_EACH_0)(func, seq)
    #define FOR_EACH_END(...)
    #define FOR_EACH_0(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_1)(func, SEQ_TAIL(seq))
    #define FOR_EACH_1(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_2)(func, SEQ_TAIL(seq))
    #define FOR_EACH_2(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_3)(func, SEQ_TAIL(seq))
    #define FOR_EACH_3(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_4)(func, SEQ_TAIL(seq))
    #define FOR_EACH_4(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_END)(func, SEQ_TAIL(seq))
    
    #define HANDLE_IF_TYPENAME(expr) FOR_EACH(HANDLE_IF_TYPENAME_IMPL, expr)
    #define HANDLE_IF_TYPENAME_IMPL(expr) std::declval<typename expr>(),
    #define HANDLE_IF_IF(expr) FOR_EACH(HANDLE_IF_IF_IMPL, expr)
    #define HANDLE_IF_IF_IMPL(expr) typename std::enable_if<expr::value>::type(),
    #define HANDLE_TRY(expr) FOR_EACH(HANDLE_TRY_IMPL, expr)
    #define HANDLE_TRY_IMPL(expr) expr,
    
    PARSE_COND(if (A)(B))              =>      typename std::enable_if<A::value>::type(), typename std::enable_if<B::value>::type(),
    PARSE_COND(try (A)(B))             =>      A, B,
    PARSE_COND(if typename (A)(B))     =>      std::declval<typename A>(), std::declval<typename B>(),
    

    2。大楼BOOST_AUTO_FUNCTION

    现在我们可以解析条件,我们几乎拥有了获得BOOST_AUTO_FUNCTION 的实际实现所需的一切。

    我们只需要另一个FOR_EACH 实现来循环传递给BOOST_AUTO_FUNCTION 的不同条件列表,以及更多的宏:

    #define FOR_EACH_I(func, seq) IIF(HAS_MORE_TOKENS(seq), FOR_EACH_I_END, FOR_EACH_I_0)(func, seq)
    #define FOR_EACH_I_END(...)
    #define FOR_EACH_I_0(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_1)(func, SEQ_TAIL(seq))
    #define FOR_EACH_I_1(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_2)(func, SEQ_TAIL(seq))
    #define FOR_EACH_I_2(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_3)(func, SEQ_TAIL(seq))
    #define FOR_EACH_I_3(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_4)(func, SEQ_TAIL(seq))
    #define FOR_EACH_I_4(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_END)(func, SEQ_TAIL(seq))
    
    
    #define TUP_SIZE(...) TUP_SIZE_IMPL(,##__VA_ARGS__,3,2,1,0)
    #define TUP_SIZE_IMPL(a,b,c,d,e,...) e
    #define TUP_TO_SEQ(...) CONCAT(TUP_TO_SEQ_, TUP_SIZE(__VA_ARGS__))(__VA_ARGS__)
    #define TUP_TO_SEQ_0()
    #define TUP_TO_SEQ_1(a) (a)
    #define TUP_TO_SEQ_2(a,b) (a)(b)
    #define TUP_TO_SEQ_3(a,b,c) (a)(b)(c)
    
    #define HANDLE_CONDS(...) FOR_EACH_I(PARSE_COND, TUP_TO_SEQ(__VA_ARGS__))
    #define INFER_RETURN_TYPE(...) ([&]() { __VA_ARGS__; })()
    #define BUILD_FUNC_BODY(...) INFER_RETURN_TYPE(__VA_ARGS__)) { __VA_ARGS__; }
    #define BOOST_AUTO_FUNCTION(signature, ...) auto signature -> decltype( HANDLE_CONDS(__VA_ARGS__) BUILD_FUNC_BODY
    

    就是这样——现在我们已经实现了BOOST_AUTO_FUNCTION:godbolt

    template< class L, class R >
    BOOST_AUTO_FUNCTION( operator -( L const& lhs, R const& rhs )
                       , if ( is_vector_udt< L > )
                            ( is_vector_udt< R > )
                       , try ( lhs + rhs )
                             ( -rhs )
                       , if typename ( L::value_type )
                       )
    (
      return lhs + -rhs
    )
    
    template< class L, class R >
    auto operator -( L const& lhs, R const& rhs ) -> decltype(
        typename std::enable_if<is_vector_udt< L >::value>::type(),
        typename std::enable_if<is_vector_udt< R >::value>::type(),
        lhs + rhs,
        -rhs,
        std::declval<typename L::value_type>(),
        ([&]() { return lhs + -rhs; })()) // <- problem
    {
        return lhs + -rhs;
    }
    

    但有一个问题 - lambdas 不能在未评估的上下文中使用(在 C++20 中它们现在可以使用,但只能在没有捕获子句的情况下使用)。
    所以不幸的是,这并没有按原样编译。

    对此也没有简单的解决方法(至少在 C++11 中 - 在 C++14 中我们可以使用自动返回类型推导) - 所以不幸的是,BOOST_AUTO_FUNCTION 无法按原样实现C++11。


    3。让它发挥作用

    使BOOST_AUTO_FUNCTION 在 C++11 中可行的一种方法是从列表中删除最后一个功能:

    1. 从给定的正文推导出返回类型;

    如果我们例如向BOOST_AUTO_FUNCTION 添加一个额外的参数,专门用于返回类型的推断:

    template< class L, class R >
    BOOST_AUTO_FUNCTION( operator -( L const& lhs, R const& rhs ),
                         lhs + -rhs // <- this will be used for return-type deduction
                       , if ( is_vector_udt< L > )
                            ( is_vector_udt< R > )
                       , try ( lhs + rhs )
                             ( -rhs )
                       , if typename ( L::value_type )
                       )
    (
      return lhs + -rhs
    )
    

    然后我们只需要稍微修改我们现有的宏就可以了:godbolt

    #define HANDLE_CONDS(...) FOR_EACH_I(PARSE_COND, TUP_TO_SEQ(__VA_ARGS__))
    #define BUILD_FUNC_BODY(...) { __VA_ARGS__; }
    #define BOOST_AUTO_FUNCTION(signature, return_type, ...) auto signature -> decltype( HANDLE_CONDS(__VA_ARGS__) return_type) BUILD_FUNC_BODY
    

    现在我们实际上有了一个有效的BOOST_AUTO_FUNCTION 实现!

    这是上面示例将生成的代码:godbolt

    template< class L, class R >
    auto operator -( L const& lhs, R const& rhs ) -> decltype(
        typename std::enable_if<is_vector_udt< L >::value>::type(),
        typename std::enable_if<is_vector_udt< R >::value>::type(),
        lhs + rhs,
        -rhs,
        std::declval<typename L::value_type>(),
        lhs + -rhs // <- expression from our additional parameter
    ) {
        return lhs + -rhs;
    }
    

    3。完整代码和Boost.PP 实现

    这是我们稍作修改的BOOST_AUTO_FUNCTION:godbolt的完整实现

    #define CONCAT_IMPL(a, b) a ## b
    #define CONCAT(a,b) CONCAT_IMPL(a, b)
    
    #define EXPAND(...) __VA_ARGS__
    #define EMPTY()
    #define DEFER(id) id EMPTY()
    
    #define HAS_MORE_TOKENS(expr) EXPAND(DEFER(HAS_MORE_TOKENS_RESULT)(HAS_MORE_TOKENS_CHECK expr, 0, 1))
    #define HAS_MORE_TOKENS_CHECK(...) ~,~
    #define HAS_MORE_TOKENS_RESULT(a, b, c, ...) c
    
    #define IIF(condition, a, b) CONCAT(IIF_, condition)(a, b)
    #define IIF_0(a, b) b
    #define IIF_1(a, b) a
    
    #define SEQ_HEAD(seq) EXPAND(DEFER(SEQ_HEAD_IMPL)(SEQ_HEAD_EL seq))
    #define SEQ_HEAD_EL(el) el,
    #define SEQ_HEAD_IMPL(head, tail) head
    #define SEQ_TAIL(seq) SEQ_TAIL_IMPL seq
    #define SEQ_TAIL_IMPL(el)
    
    #define FOR_EACH(func, seq) IIF(HAS_MORE_TOKENS(seq), FOR_EACH_END, FOR_EACH_0)(func, seq)
    #define FOR_EACH_END(...)
    #define FOR_EACH_0(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_1)(func, SEQ_TAIL(seq))
    #define FOR_EACH_1(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_2)(func, SEQ_TAIL(seq))
    #define FOR_EACH_2(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_3)(func, SEQ_TAIL(seq))
    #define FOR_EACH_3(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_4)(func, SEQ_TAIL(seq))
    #define FOR_EACH_4(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_END, FOR_EACH_END)(func, SEQ_TAIL(seq))
    
    #define FOR_EACH_I(func, seq) IIF(HAS_MORE_TOKENS(seq), FOR_EACH_I_END, FOR_EACH_I_0)(func, seq)
    #define FOR_EACH_I_END(...)
    #define FOR_EACH_I_0(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_1)(func, SEQ_TAIL(seq))
    #define FOR_EACH_I_1(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_2)(func, SEQ_TAIL(seq))
    #define FOR_EACH_I_2(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_3)(func, SEQ_TAIL(seq))
    #define FOR_EACH_I_3(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_4)(func, SEQ_TAIL(seq))
    #define FOR_EACH_I_4(func, seq) func(SEQ_HEAD(seq)) IIF(HAS_MORE_TOKENS(SEQ_TAIL(seq)), FOR_EACH_I_END, FOR_EACH_I_END)(func, SEQ_TAIL(seq))
    
    
    #define TUP_SIZE(...) TUP_SIZE_IMPL(,##__VA_ARGS__,3,2,1,0)
    #define TUP_SIZE_IMPL(a,b,c,d,e,...) e
    #define TUP_TO_SEQ(...) CONCAT(TUP_TO_SEQ_, TUP_SIZE(__VA_ARGS__))(__VA_ARGS__)
    #define TUP_TO_SEQ_0()
    #define TUP_TO_SEQ_1(a) (a)
    #define TUP_TO_SEQ_2(a,b) (a)(b)
    #define TUP_TO_SEQ_3(a,b,c) (a)(b)(c)
    
    
    #define COND_if    HANDLE_IF (
    #define COND_try   HANDLE_TRY (
    
    #define COND_IF_typename HANDLE_IF_TYPENAME (
    
    #define HANDLE_IF(expr) IIF(HAS_MORE_TOKENS(expr), HANDLE_IF_MORE, HANDLE_IF_IF)(expr)
    #define HANDLE_IF_MORE(expr) CONCAT(COND_IF_,expr))
    
    #define HANDLE_IF_TYPENAME(expr) FOR_EACH(HANDLE_IF_TYPENAME_IMPL, expr)
    #define HANDLE_IF_TYPENAME_IMPL(expr) std::declval<typename expr>(),
    #define HANDLE_IF_IF(expr) FOR_EACH(HANDLE_IF_IF_IMPL, expr)
    #define HANDLE_IF_IF_IMPL(expr) typename std::enable_if<expr::value>::type(),
    #define HANDLE_TRY(expr) FOR_EACH(HANDLE_TRY_IMPL, expr)
    #define HANDLE_TRY_IMPL(expr) expr,
    
    #define PARSE_COND(expr) CONCAT(COND_,expr))
    
    #define HANDLE_CONDS(...) FOR_EACH_I(PARSE_COND, TUP_TO_SEQ(__VA_ARGS__))
    #define BUILD_FUNC_BODY(...) { __VA_ARGS__; }
    #define BOOST_AUTO_FUNCTION(signature, return_type, ...) auto signature -> decltype( HANDLE_CONDS(__VA_ARGS__) return_type) BUILD_FUNC_BODY
    
    
    
    // Usage:
    template< class L, class R >
    BOOST_AUTO_FUNCTION( operator -( L const& lhs, R const& rhs ),
                         lhs + -rhs
                       , if ( is_vector_udt< L > )
                            ( is_vector_udt< R > )
                       , try ( lhs + rhs )
                             ( -rhs )
                       , if typename ( L::value_type )
                       )
    (
      return lhs + -rhs
    )
    

    使用 Boost 预处理器,我们可以减少大量样板宏代码。

    这是使用 boost pp 的相同实现的外观:godbolt

    #include <boost/preprocessor.hpp>
    
    #define COND_if    HANDLE_IF (
    #define COND_try   HANDLE_TRY (
    
    #define COND_IF_typename HANDLE_IF_TYPENAME (
    
    #define HANDLE_IF(expr) BOOST_PP_IIF(BOOST_PP_IS_BEGIN_PARENS(expr), HANDLE_IF_IF, HANDLE_IF_MORE)(expr)
    #define HANDLE_IF_MORE(expr) BOOST_PP_CAT(COND_IF_,expr))
    
    #define HANDLE_IF_TYPENAME(expr) BOOST_PP_SEQ_FOR_EACH(HANDLE_IF_TYPENAME_IMPL, ~, expr)
    #define HANDLE_IF_TYPENAME_IMPL(r, _, expr) std::declval<typename expr>(),
    #define HANDLE_IF_IF(expr) BOOST_PP_SEQ_FOR_EACH(HANDLE_IF_IF_IMPL, ~, expr)
    #define HANDLE_IF_IF_IMPL(r, _, expr) typename std::enable_if<expr::value>::type(),
    #define HANDLE_TRY(expr) BOOST_PP_SEQ_FOR_EACH(HANDLE_TRY_IMPL, ~, expr)
    #define HANDLE_TRY_IMPL(r, _, expr) expr,
    
    #define PARSE_COND(r, _, i, expr) BOOST_PP_CAT(COND_,expr))
    
    #define TUP_TO_SEQ(...) BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))
    #define HANDLE_CONDS(...) BOOST_PP_SEQ_FOR_EACH_I( PARSE_COND, ~, TUP_TO_SEQ(__VA_ARGS__))
    #define BUILD_FUNC_BODY(...) { __VA_ARGS__; }
    #define BOOST_AUTO_FUNCTION(signature, return_type, ...) auto signature -> decltype( HANDLE_CONDS(__VA_ARGS__) return_type) BUILD_FUNC_BODY
    

    4。其他资源

    【讨论】:

      猜你喜欢
      • 2022-11-24
      • 1970-01-01
      • 2021-12-12
      • 2016-01-17
      • 2022-11-02
      • 2020-04-16
      • 1970-01-01
      • 2017-05-06
      • 1970-01-01
      相关资源
      最近更新 更多