首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++中添加语法糖

在C++中添加语法糖
EN

Stack Overflow用户
提问于 2022-02-08 02:38:06
回答 2查看 222关注 0票数 3

编辑2:

新编辑:看起来C++20有一个新的范围库,从功能的角度来看,它可以做我想做的事情。如何在C++17或更早的时候做类似的事情?另外,Kotlin的语法糖也可能吗?主要是人的例子:

代码语言:javascript
复制
val adam = Person("Adam").apply { 
    age = 20 // same as this.age = 20 or adam.age = 20
    city = "London"
}

编辑1:

我不知道我的问题是否那么清楚,所以我会用Rust的地图给出一个例子。

这就是地图是如何在锈蚀中完成的:

代码语言:javascript
复制
let newVector = myVector.iter().map(|x|, x * 2)

这是如何在C++中完成的

代码语言:javascript
复制
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; });

这要详细得多。

我想添加一些语法糖来做这样的事情:

代码语言:javascript
复制
std::string s("hello");
auto ordinals = my_ns::map(s,[](unsigned char c) -> std::size_t { return c; });

my_ns::map的实现可以是这样的(我相信这是行不通的,它只是为了展示它是如何实现的)

代码语言:javascript
复制
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;
}

在这种情况下,ordinals不需要是std::vector<std::size_t>类型,它可以是具有std::vector<T>转换的map类型。类型映射的原因是能够将函数链接起来,例如,使用map来减少。

原始问题

注意:这只是一个个人项目,我不打算使用它在生产或在大多数时候使用C++。

最近我使用了大量的Kotlin,我对Rust有点兴趣,我喜欢他们更高层次的功能。这让我想知道,我能创造一些语法糖来模仿这些特性吗?

我会试图模仿的一些东西(只是一个例子)

锈图:

代码语言:javascript
复制
let newVector = myVector.iter().map(|x|, x * 2)

科特林

代码语言:javascript
复制
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}")
}

我不打算使用完全相同的语法,但我想知道是否可以这样做:

代码语言:javascript
复制
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

第一个kotlin让我不知道怎么做,但是第二个也可以用lambdas来解决。

我正在考虑使用新的类型,并创建到std::向量和数组的转换,这是C#的LINQ的工作方式之一。

任何关于如何做到这一点的建议都是值得赞赏的。

Ps:我知道std::transform和其他函数(我可能会在实现这些函数时使用它们),但是我想要一个比提供的API更简单的API(而且我也认为这是一个很好的个人项目)。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-02-08 03:12:28

您的示例可以很容易地更改为工作C++代码:

代码语言:javascript
复制
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;
}

这既不是非常惯用的,也不是对性能进行优化的,但它是有效的。(预先调整矢量的大小,而不是使用std::back_inserter,通过引用传递t,从而大大提高性能。)

编辑:您可以按以下方式添加reduce

代码语言:javascript
复制
template <typename T, typename R, typename Fun> auto reduce(T t, R init, Fun f) {
  return std::transform(t.begin(), t.end(), init, f);
}

然后将它们结合起来:reduce(map(x, [](auto a) {...}), 0, [](int& a, auto b) {...})

显而易见的警告是:这将是非常缓慢的。这些函数学习模板概念很有趣,但在实践中,范围或旧风格的std::reduce/.会快得多。

编辑2:如果您想使用map作为成员函数,只需创建一个包装类:

代码语言:javascript
复制
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}; }

然后你就可以做wrap(my_vec).map(...).reduce(..., ...)

for循环在这里会更快,因为您正在进行大量不必要的复制:您不必要地在map中创建一个新向量并多次复制数据(std::back_inserter,按值传递)。

票数 2
EN

Stack Overflow用户

发布于 2022-02-08 03:10:53

我想知道是否可以这样做:

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

在C++标准库中,这个意义上的"map“称为"transform”。一个有用的例子:

代码语言:javascript
复制
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_);

可以用地图链接像reduce这样的函数。

你可以缩小范围。不幸的是,C++20标准范围并没有提供一个约简函数,因此必须使用另一个范围实现,或者使用基于迭代器的函数。后一种情况的例子:

代码语言:javascript
复制
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
     );

到std::向量的转换

还可以从范围内创建容器:

代码语言:javascript
复制
std::vector doubled_vector(
    doubled_view.begin(), doubled_view.end());

请注意,为范围视图的中间阶段创建容器可能会带来不必要的开销。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71027960

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档