定制 C++预处理器/类型宏

发布于 2024-08-09 00:20:41 字数 699 浏览 2 评论 0原文

看到了 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);
}

最终,我希望能够使用最少量的样板代码对 inst 进行任意排序。我能想到的最简单的方法是利用 STL 的排序:

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

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

sort(vec,a ASC,b DESC);

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

实现我的梦想的最佳方式是什么?如果我有某种类型的宏,它会向我揭示向量元素的类型,那么编写 C 预处理器宏来创建排序所需的函数就很简单了。

另一种选择似乎是编写我自己的预处理器。这很有效,直到我必须再次推断出“vec”的类型。有没有简单的方法可以做到这一点?

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

Having seen the advantages of metaprogramming in Ruby and Python, but being bound to lower-level languages like C++ and C for actual work, I'm thinking of manners by which to combine the two. One instance comes in the simple problem for sorting lists of arbitrary structures/classes. For instance:

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);
}

Ultimately, I'd like to be able to sort inst arbitrarily with a minimal amount of boilerplate code. The easiest way I can see to do this is to make use of STL's sort:

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

Yet this requires me to write a method that can compare "struct s"s. What I'd rather do is:

sort(vec,a ASC,b DESC);

Which is very clearly not valid C++.

What is the best way to accomplish my dream? If I had some sort of typeful macro, that would reveal to me what the type of a vector's elements were, then it would be trivial to write C preprocessor macros to create the function required to do the sorting.

The alternative seems to be to write my own preprocessor. This works well, up until the point where I have to deduce the type of "vec" again. Is there an easy way to do this?

Context: Less code = less bugs, programming competitions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

看海 2024-08-16 00:20:41

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

using namespace boost::lambda;

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

这当然假设您按 a 排序。

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

警告:上面的代码未经测试。

希望这有帮助!

For the above, you can use Boost.Lambda to write your comparison function inline, just like a Python lambda:

using namespace boost::lambda;

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

This of course assumes that you are sorting by a.

If the expressions you are looking for are far more complex, you are better off writing a separate function; even in languages like Python and Ruby with native support for closures, complex closures become quite unreadable anyway.

Warning: The code above is untested.

Hope this helps!

遇到 2024-08-16 00:20:41

我会坚持为 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));
}

这段代码未经测试,但您已经明白了。

I would stick with writing a comparison operator for the struct. The bonus of having a comparison operator defined is that you don't end up with multiple lambda comparisons scattered all over the place. Chances are that you will need a comparison operator more than just once, so why not define it once in the logical place (along with the type)?

Personally, I prefer writing code once and keeping it some place that is particularly easy to find. I also favor writing code that is idiomatic with respect to the language that I am writing in. In C++, I expect constructors, destructors, less-than operators, and the like. You are better off writing a less-than operator and then letting std::sort(vec.begin(), vec.end()) do its proper job. If you really want to make your code clear, then do something like:

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

If you define a member function to do the comparison and then provide the operator at the namespace-level, life is much easier when you have to negate the comparison. For example:

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

This code is untested but you get the idea.

-黛色若梦 2024-08-16 00:20:41

如果您使用的是 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; }); 

两者在功能上是等效的。

If you are using C++11, you can use Linq to sort it like this:

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

Or if you don't like the query syntax, you can use the extension methods as well:

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

Both are functionally equivalent.

野心澎湃 2024-08-16 00:20:41

对于 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);

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

简而言之,使用现代 C++,您将不需要特殊的预处理器来实现你正在尝试做的事。

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

For c++ the standard library offers the algorithms header which contains many useful functions that work on various containers. An example for your purposes would be:

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 has a prototype that looks something like:

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

Most of these algorithms should work for any of the standard containers (some are specific to sorted containers, some associative, etc). I believe sort (and others) will even work with arrays (Iterators, the foundation of algorithms, are built to emulate pointers to array elements as closely as possible.)

In short, using modern c++ you will not need a special preprocessor to achieve what you're trying to do.

BTW, if you've declared that you're using std or std::sort, then sort(vec.begin(),vec.end()) is valid c++;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文