Uniform Function Call Syntax

导语

现在手头有一个库,只有头文件和共享库(.so、.dll whatever),需要对头文件中的类增加方法,可是这个类标记了final,这时候该怎么办呢?

Rust的做法

现在有一个简单的库叫做Point, 这个库只有两个方法newenlarge现在需要为其添加新的功能,即:shrink。可以这么做: Rust Traits 当然, 如果有多个trait都提供了同样的接口,这时候就需要消歧义了,Rust的做法是这样

trait Foo {
  fn moha(&self);
}

trait Bar {
  fn moha(&self);
}

struct Elder;

impl Foo for Elder {
  fn moha(&self) {
    println!("+1s");
  }
}

impl Bar for Elder {
  fn moha(&self) {
    println!("-1s");
  }
}

fn main() {
  let elder = Elder;
  <Elder as Foo>::moha(&elder); // print `+1s`
  <Elder as Bar>::moha(&elder); // print `-1s`
}

看到这里, 你可能已经发现, 在Rust里面 elder.moha()Foo::moha(&elder)是等价的。

C++的做法

#include <iostream>

struct Point {
  int x;
  int y;
  static auto New() -> Point {
    return Point {0, 0};
  }

  auto enlarge() -> Point&  {
    this->x += 2;
    this->y += 2;
    return *this;
  }
};

std::ostream& operator<< (std::ostream& os, const Point& p) {
  os << "Point { x: " << p.x << ", y: " << p.y << " }\n";
  return os;
}

struct MyPoint : Point {
  auto shrink() -> Point&  {
    this->x -= 2;
    this->y -= 2;
    return *this;
  }
};

int main() {
  MyPoint mp;
  std::cerr << mp;
  mp.enlarge();
  std::cerr << mp;
  mp.shrink();
  std::cerr << mp;
}

现在有两个明显的问题:

那么,可不可以这样

// define a method for Point
auto shrink(Point& p) -> Point& {
  p.x -= 2;
  p.y -= 2;
  return p;
}

// then call it
p.shrink();

这里以Rust扩展方法的做法为例子其实并不很恰当。目的为了与final修饰的C++类的扩展做对比。 上面shrink只是一个普通的函数,但通过.shrink来调用,正是uniform function call的一部分。

摘自A bit of backgorund for unified call proposal的一段话: > So, we are left with a simple proposal to allow f(x,y) to find x.f(y) where f(x,y) wouldn’t work today. This solves the problem for library writers and their users along the lines of the STL:

UFCS与Concepts

待续…

参考

Rust UFCS RFC
C++ UFCS Proposal
background for unified call proposal
UFCS Wiki
N4474