【问题标题】:Custom C++ Preprocessor / Typeful Macros自定义 C++ 预处理器/类型宏
【发布时间】:2009-10-18 23:59:50
【问题描述】:

看到 Ruby 和 Python 中元编程的优势,但在实际工作中受限于 C++ 和 C 等低级语言,我正在考虑将两者结合起来的方式。一个例子是对任意结构/类的列表进行排序的简单问题。例如:

struct s{
  int a;
  int b;
};

vector<s> vec;
for(int x=0;x<10;x++){
  s inst;
  inst.a = x;
  inst.b = x+10;
  vec.push_back(inst);
}

最终,我希望能够使用最少的样板代码任意排序。我能看到的最简单的方法是使用 STL 的排序:

sort(vec.begin(),vec.end());

但这需要我编写一个可以比较“struct s”的方法。我宁愿做的是:

sort(vec,a ASC,b DESC);

这显然不是有效的 C++。

实现梦想的最佳方式是什么?如果我有某种类型的宏,它将向我揭示向量元素的类型,然后编写 C 预处理器宏来创建执行排序所需的函数将是微不足道的。

替代方法似乎是编写我自己的预处理器。这很好用,直到我不得不再次推断出“vec”的类型。有没有简单的方法可以做到这一点?

背景:更少的代码 = 更少的错误,编程竞赛。

【问题讨论】:

    标签: c++ macros c-preprocessor metaprogramming type-inference


    【解决方案1】:

    对于上述情况,您可以使用Boost.Lambda 内联编写您的比较函数,就像 Python lambda 一样:

    using namespace boost::lambda;
    
    std::sort(vec.begin(), vec.end(), (_1 ->* &s::a) < (_2 ->* &s::a));
    

    这当然假设您是按 a 排序的。

    如果您要查找的表达式要复杂得多,最好编写一个单独的函数;即使在 Python 和 Ruby 等原生支持闭包的语言中,复杂的闭包也变得非常不可读。

    警告:以上代码未经测试。

    希望这会有所帮助!

    【讨论】:

    • 太棒了,我知道必须有人使用模板来完成这项工作。谢谢!
    【解决方案2】:

    我会坚持为struct 编写一个比较运算符。定义比较运算符的好处是,您最终不会得到分散在各处的多个 lambda 比较。您可能不止一次需要比较运算符,那么为什么不在逻辑位置(连同类型)定义一次呢?

    就个人而言,我更喜欢编写一次代码并将其保存在特别容易找到的地方。我也喜欢编写与我正在编写的语言相关的惯用代码。在 C++ 中,我期望构造函数、析构函数、小于运算符等。您最好编写一个小于运算符,然后让std::sort(vec.begin(), vec.end()) 完成其应有的工作。如果你真的想让你的代码更清晰,那么请执行以下操作:

    struct S {
        int a, b;
        bool less_than(S const& other) {...};
    };
    bool operator<(S const& left, S const& right) {
        return left.less_than(right);
    }
    

    如果您定义一个成员函数来进行比较,然后在命名空间级别提供运算符,那么当您必须否定比较时,生活会容易得多。例如:

    void foo(std::vector<S>& svec) {
        std::sort(svec.begin(), svec.end(), std::not1(&S::less_than));
    }
    

    此代码未经测试,但您明白了。

    【讨论】:

      【解决方案3】:

      如果你使用的是C++11,可以使用Linq这样排序:

      auto q = LINQ(from(x, vec) orderby(ascending x.a, descending x.b));
      

      或者如果你不喜欢查询语法,你也可以使用扩展方法:

      auto q = vec | linq::order_by([](s x) { return x.a; }) 
                   | linq::then_by_descending([](s x) { return x.b; }); 
      

      两者在功能上是等效的。

      【讨论】:

        【解决方案4】:

        对于 c++,标准库提供了 algorithms 标头,其中包含许多适用于各种容器的有用函数。适合您的示例是:

        bool sCompare(const s & s1, const s & s2) {
        return s1.a+s1.b/1000 < s2/a+s2.b/1000;
        }
        
        vector<s> vec;
        ...
        std::sort(vec.begin(), vec.end(), sCompare);
        

        sort 的原型类似于:

        template<class Iter, class Op>
        void sort(Iter& start, Iter& stop, Op&  op);
        

        这些算法中的大多数应该适用于任何标准容器(一些特定于排序容器,一些关联容器等)。我相信 sort(和其他)甚至可以与数组一起使用(迭代器是算法的基础,旨在尽可能地模拟指向数组元素的指针。)

        简而言之,使用现代 c++,您将不需要特殊的预处理器来实现您想要做的事情。

        顺便说一句,如果您声明您使用的是 std 或 std::sort,那么 sort(vec.begin(),vec.end()) 有效的 c++;

        【讨论】:

          猜你喜欢
          • 2011-01-26
          • 2010-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多