使用类型类使OpenGL的int常量类型安全

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用类型类使OpenGL的int常量类型安全相关的知识,希望对你有一定的参考价值。

我想在lwjgl周围创建一个类型安全的包装器。最重要的是,我希望它是一个编译时错误,将错误的常量传递给函数,例如叫glEnable(GL_ARRAY_BUFFER)。如果它不是针对支持同一函数的不同常量的不同上下文,那么这将是相当容易的。

我想我会使用类型类来模拟哪些常量可以传递给哪个函数。我有一个解决方案,但不可否认它有点难看并且未能应用某个隐含的:

trait GlConst { val glConst: Int }

trait GlConstCompanion[C <: GlConst] { val instance: C }


class GlDepthTest private () extends GlConst { val glConst = GL_DEPTH_TEST }

object GlDepthTest extends GlConstCompanion[GlDepthTest] {
  val instance = new GlDepthTest
}


class GlLineSmooth private () extends GlConst { val glConst = GL_LINE_SMOOTH }

object GlLineSmooth extends GlConstCompanion[GlLineSmooth] {
  val instance = new GlLineSmooth
}


class GlArrayBuffer private () extends GlConst { val glConst = GL_ARRAY_BUFFER }

object GlArrayBuffer extends GlConstCompanion[GlArrayBuffer] {
  val instance = new GlArrayBuffer
}


// type class for arguments to glEnable
trait GlEnableCap[T <: GlConst] extends GlConst


object GlContext33 {
  implicit object GlDepthTestIsEnableCap extends GlEnableCap[GlDepthTest] {
    val glConst = GlDepthTest.instance.glConst
  }

  implicit object GlLineSmoothIsEnableCap extends GlEnableCap[GlLineSmooth] {
    val glConst = GlLineSmooth.instance.glConst
  }

  def glEnable[T <: GlConst : GlEnableCap](t: T): Unit = println(implicitly[GlEnableCap[T]].glConst)
}

object Test extends App {
  import GlContext33._

  implicit def constComp2Const[C <: GlConst](cc: GlConstCompanion[C]): C = cc.instance

  // works
  glEnable(GlDepthTest.instance)

  // fails to apply implicit glConstComp2Comp
  glEnable(GlDepthTest)

  // fails intentionally
  glEnable(GlArrayBuffer)
}

有没有办法让隐含工作?或者是否有更好的方法来包装OpenGL的常量?

答案

根据经验,如果您不需要,请不要使用implicits。在这种情况下,您只需使用类型边界即可解决它:

// Start writing your ScalaFiddle code here

val GL_DEPTH_TEST = 1
val GL_LINE_SMOOTH = 1
val GL_ARRAY_BUFFER = 1


trait GlConstCap

trait GlEnableConstCap extends GlConstCap
trait GlBufferConstCap extends GlConstCap

trait GlConst[C <: GlConstCap] { val value: Int }

object GlDepthTest extends GlConst[GlEnableConstCap] {
  val value = GL_DEPTH_TEST
}

object GlLineSmooth extends GlConst[GlEnableConstCap] {
  val value = GL_LINE_SMOOTH
}

object GlArrayBuffer extends GlConst[GlBufferConstCap] {
  val value = GL_ARRAY_BUFFER
}


object GlContext33 {
  def glEnable[T <: GlConst[GlEnableConstCap]](t: T): Unit = println(t.value)
}

object Test extends App {
  import GlContext33._

  // works
  glEnable(GlDepthTest)

  // fails to apply implicit glConstComp2Comp
  glEnable(GlDepthTest)

  // fails intentionally
  glEnable(GlArrayBuffer)
}

Try it out!

注意:如果你想创建更深层次的C继承结构,你可能想在GlConst中添加GlConstCap的逆变。


我希望这有帮助。

以上是关于使用类型类使OpenGL的int常量类型安全的主要内容,如果未能解决你的问题,请参考以下文章

引用的实质和常量的使用

使用驱动程序不支持的更高版本 OpenGL 的常量是不是安全?

枚举类的使用方法

用枚举enum替代int常量

java 类字面常量,泛化的Class引用

常量与变量的数据类型转换