c++ - Scala 可变数量的参数是 F-Bounded 类型的子类

标签 c++ scala types generic-programming f-bounded-polymorphism

在 C++ 中,我可以创建一个可变函数模板,如下所示:

#include <tuple>

// helper to loop over tuple
template <std::size_t I = 0, typename FuncT, typename... Args>
void for_each(std::tuple<Args...>& tuple, FuncT func) {
  func(std::get<I>(tuple));
  if constexpr (I + 1 < sizeof...(Args)) {
    for_each<I + 1, FuncT, Args...>(tuple, func);
  }
}

template <class A, class B, class Derived>
struct FBounded {
  auto foo() { return static_cast<Derived *>(this); }
  auto baz() { return static_cast<Derived *>(this); }
};

class Child1 : public FBounded<const char*, const char*, Child1> {};
class Child2 : public FBounded<bool, int, Child2> {};
class Child3 : public FBounded<double, const char*, Child3> {};

template <class... A, class... B, class... SubTypes>
static auto func(FBounded<A, B, SubTypes>... elems) {
  auto args = std::tuple(elems...);
  for_each(args, [](auto x) { x.foo()->baz(); });
}

int main() {
  auto c1 = Child1();
  auto c2 = Child2();
  auto c3 = Child3();

  func(c1, c2, c3);
}

我想在 Scala 中重新创建此行为。这是我目前所拥有的:

class FBounded[A, B, T <: FBounded[A, B, T]] {
  def foo(): T = this.asInstanceOf[T]
  def baz(): T = this.asInstanceOf[T]
}

class Child1 extends FBounded[Int, Double, Child1] {}
class Child2 extends FBounded[String, String, Child2] {}
class Child3 extends FBounded[Int, String, Child3] {}

def func(elems: Seq[FBounded[_, _, _]]) = {
    elems.foreach(_.foo.baz)
}


val c1 = new Child1()
val c2 = new Child2()
val c3 = new Child3()

func(c1, c2, c3)

我收到错误:

error: value baz is not a member of _$3
elems.foreach(_.foo.baz)
              ^

我相信这与 Scala 何时填充占位符类型有关,但我不确定。

最佳答案

FBounded[_, _, _] 类型是存在类型的快捷方式,看起来有点像

FBounded[A, B, T] forSome { type A; type B; type T <: FBounded[A, B, T] }

并且出于某种原因,编译器拒绝为类型参数 T 推断正确的 f-bounds(至少我无法做到这一点)。

我想这可能以某种方式与为什么 existential types are dropped in Dotty 的原因有关。 .

这是一个完全避免存在类型的变通方法:

class FBounded[A, B, T <: FBounded[A, B, T]] {
  self: T =>
  def foo: T = self
  def baz: T = self
  def wrap: FBE = new FBE {
    type a = A
    type b = B
    type t = T
    val value: t = self
  }
}

class Child1 extends FBounded[Int, Double, Child1] {}
class Child2 extends FBounded[String, String, Child2] {}
class Child3 extends FBounded[Int, String, Child3] {}

/** Wrapper for FBounded existential types */
abstract class FBE {
  type a
  type b
  type t <: FBounded[a, b, t]
  val value: t
}

def func(elems: FBE*) = {
  elems.map(_.value.foo.baz)
}

val c1 = new Child1()
val c2 = new Child2()
val c3 = new Child3()

func(c1.wrap, c2.wrap, c3.wrap)

它不依赖于存在的FBounded[_, _, _],而是使用一个包装类FBE,它包含一个包含所有类型和所有约束的长列表.使用 FBEfunc 似乎工作得很好:

def func(elems: FBE*) = {
  elems.map(_.value.foo.baz)
}

因为它可以更明确地写成:

def funcMoreExplicit(elems: FBE*) = {
  elems.map(e => {
    val v: e.t = e.value
    val fooRes: e.t = v.foo
    val bazRes: e.t = fooRes.baz
    bazRes
  })
}

我们可以在其中使用 FBE.t 提供的显式路径相关类型 e.t 获取中间结果。

关于c++ - Scala 可变数量的参数是 F-Bounded 类型的子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51788569/

相关文章:

mongodb - Scala Play Salat 聚合示例

scala - 在 Scala Specs2 中重用 "await"参数

C++ : Swapping template class elements of different types?

python - isinstance(type, object) = True,为什么?

c++ - 直接声明变量和使用关键字new有什么区别?

c++ - 将相似类型的成员变量分组在一起

c++ - 编译错误: no class template, 初始化器太多,没有匹配的函数

c++ - 错误消息 "invalid conversion from ‘void*’ 到 ‘unsigned int’“

scala - 使用 nth 的二维插值

c++ - 如何为我的数组选择更大的数据类型?