简体   繁体   English

给 C++ 添加语法糖

[英]Adding syntactic sugar to C++

Edit 2:编辑 2:

New edit: it looks like C++20 has a new ranges library, which does what I want from the functional point of view.新编辑:看起来 C++20 有一个新的范围库,从功能的角度来看,它可以满足我的要求。 How would something similar be done on C++17 or earlier?如何在 C++17 或更早的时间完成类似的事情? Also, would the Kotlin syntactic sugar be possible?另外, Kotlin 语法糖可能吗? Mainly the person example:主要是人的例子:

val adam = Person("Adam").apply { 
    age = 20 // same as this.age = 20 or adam.age = 20
    city = "London"
}

Edit 1:编辑 1:

I don't know if my question was that clear, so I'll give an example using Rust's map.我不知道我的问题是否那么清楚,所以我将使用 Rust 的 map 举个例子。

This is how a map is done in rust:这是在 rust 中完成 map 的方式:

let newVector = myVector.iter().map(|x|, x * 2)

This is how it is done in C++ C++中是这样实现的

std::string s("hello");
std::vector<std::size_t> ordinals;
std::transform(s.begin(), s.end(), std::back_inserter(ordinals),
     [](unsigned char c) -> std::size_t { return c; });

This is a lot more verbose.这要冗长得多。

I'd like to add some syntactic sugar to do something like this instead:我想添加一些语法糖来做这样的事情:

std::string s("hello");
auto ordinals = my_ns::map(s,[](unsigned char c) -> std::size_t { return c; });

The implementation of my_ns::map could be something like this (I'm sure this will not work, it's just to show how it could be done) my_ns::map 的实现可能是这样的(我确定这行不通,只是为了展示它是如何完成的)

template<typename T, U>
map(T t, std::function<U> f)
{
    std::vector<U> ordinals;
    std::transform(t.begin(), t.end(), std::back_inserter(ordinals),
     [](U c) -> f(c));
    return ordinals;
}

In this case ordinals doesn't need to be of type std::vector<std::size_t> , it could be of a type map which has a conversion for std::vector<T> .在这种情况下, ordinals不需要是std::vector<std::size_t>类型,它可以是map类型,它具有std::vector<T>的转换。 The reason for a type map is to be able to chain functions like reduce with map.类型 map 的原因是能够将 reduce 等函数与 map 链接起来。

Original Question原始问题

Note: this is for a personal project only, I do not intend to use it in production or when working with C++ most of the time.注意:这仅适用于个人项目,我不打算在生产中或大部分时间使用 C++ 时使用它。

I have been using a lot of Kotlin lately and I'm dabbling a little with Rust and I love their higher level features.我最近一直在使用很多 Kotlin,我正在涉足 Rust,我喜欢它们的高级功能。 That got me wondering, can I create some syntactic sugar to emulate some of these features?这让我想知道,我可以创建一些语法糖来模拟其中的一些功能吗?

Some of the stuff I'd be trying to emulate(just an example)我会尝试模仿的一些东西(只是一个例子)

Rust map: Rust map:

let newVector = myVector.iter().map(|x|, x * 2)

Kotlin let Kotlin 让

val adam = Person("Adam").apply { 
    age = 20 // same as this.age = 20 or adam.age = 20
    city = "London"
}

val str = "Hello"
str.let {
   println("The string's length is ${it.length}")
}

I do not plan on using the exact same syntax, but I'd like to know if it would be possible to do something like:我不打算使用完全相同的语法,但我想知道是否可以这样做:

int[] arr = {1, 2, 3};
auto d_arr = map(arr, [](int x){return x*2}) // maybe return a map type to be able to use .reduce, etc

The first kotlin let example I wouldn't know how to do, but the second could be solved using lambdas as well.第一个 kotlin 让我不知道该怎么做,但第二个也可以使用 lambda 来解决。

I'm thinking of using new types and create conversions to std::vector and arrays, kind of how C#'s LINQ works.我正在考虑使用新类型并创建到 std::vector 和 arrays 的转换,类似于 C# 的 LINQ 的工作方式。

Any tips on how to do this are appreciated.任何有关如何执行此操作的提示都将受到赞赏。

Ps: I know about std::transform and other functions(I'd probably use them when implementing this), but I'd like a simpler API than the ones offered (and I also think that it would be a nice personal project). Ps:我知道 std::transform 和其他功能(我可能会在实现时使用它们),但我想要一个比提供的更简单的 API (我也认为这将是一个不错的个人项目) .

Your example can be changed to working C++ code fairly easily:您的示例可以很容易地更改为工作 C++ 代码:

template <typename T, typename Fun> auto map(T t, Fun f) {
  std::vector<typename T::value_type> ordinals;
  std::transform(t.begin(), t.end(), std::back_inserter(ordinals), f);
  return ordinals;
}

This is neither very idiomatic nor optimized for performance, but it works.这既不是很惯用也不是针对性能优化的,但它确实有效。 (Pre-resize the vector instead of using std::back_inserter and pass t by reference for a big performance boost.) (预先调整向量的大小而不是使用std::back_inserter并通过引用传递t以获得巨大的性能提升。)

Edit: You can add reduce as follows:编辑:您可以按如下方式添加reduce

template <typename T, typename R, typename Fun> auto reduce(T t, R init, Fun f) {
  return std::transform(t.begin(), t.end(), init, f);
}

And then combine them: reduce(map(x, [](auto a) {...}), 0, [](int& a, auto b) {...})然后组合它们: reduce(map(x, [](auto a) {...}), 0, [](int& a, auto b) {...})

The obvious caveat: This is going to be really slow.明显的警告:这将非常缓慢。 These functions are fun to learn template concepts, but in practice, ranges or old-style std::reduce /... will be much, much faster.这些函数对于学习模板概念很有趣,但在实践中,范围或旧式std::reduce /... 会快得多。

Edit 2: If you want to use map as a member function, just make a wrapper class:编辑 2:如果你想使用map作为成员 function,只需制作一个包装器 class:

template<class T>
struct Wrapper {
  T d;
  template <typename Fun> auto map(Fun f) {
    std::vector<typename T::value_type> ordinals;
    std::transform(d.begin(), d.end(), std::back_inserter(ordinals), f);
    return wrap(ordinals);
  }
  template <typename R, typename Fun> auto reduce(R init, Fun f) {
    return wrap(std::transform(d.begin(), d.end(), init, f));
  }
};
template<class T> Wrapper<T> wrap(const T& t) { return {t}; }
template<class T> Wrapper<T> wrap(T&& t) { return {t}; }

Then you can do wrap(my_vec).map(...).reduce(..., ...)然后你可以做wrap(my_vec).map(...).reduce(..., ...)

for loops would be faster here, because you're doing a lot of unnecessary copying: you're unnecessarily creating a new vector in map and copy data lots of times ( std::back_inserter , pass-by-value). for循环在这里会更快,因为你做了很多不必要的复制:你不必要地在map中创建一个新向量并多次复制数据( std::back_inserter ,按值传递)。

I'd like to know if it would be possible to do something like:我想知道是否可以做类似的事情:

 int[] arr = {1, 2, 3}; auto d_arr = map(arr, [](int x){return x*2})

"map" in this sense is called "transform" in C++ standard library.这个意义上的“地图”在C++标准库中被称为“变换”。 A working example:一个工作示例:

auto double_ = [](auto x){ return x*2; }; // you may also use a normal function
auto doubled_view = std::views::all(arr)
                  | std::views::transform(double_);

to be able to chain functions like reduce with map.能够将 reduce 等函数与 map 链接起来。

You can reduce ranges.您可以缩小范围。 Unfortunately, the C++20 standard ranges don't come with a reduce function, so one has to use either another implementation of ranges, or use the iterator based functions instead.不幸的是,C++20 标准范围没有附带 reduce function,因此必须使用范围的另一种实现,或者改用基于迭代器的函数。 Example of latter:后者的例子:

auto sum = std::reduce(
     std::execution::unseq, // optional execution policy
     doubled_view.begin(),
     doubled_view.end(),
     0
     // you can use a functor to do something other than add
     );

conversions to std::vector转换为 std::vector

You can also create containers from ranges:您还可以从范围创建容器:

std::vector doubled_vector(
    doubled_view.begin(), doubled_view.end());

Note that creating containers for intermediate stages of range views can have unnecessary overhead.请注意,为范围视图的中间阶段创建容器可能会产生不必要的开销。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM