C++中 template cast ( 以Sophus库为例 )

1,186 阅读1分钟

作者: 边城量子 ( shihezichen@live.cn )

背景

在阅读 Sophus 库代码时, 经常会遇到 template cast 的使用, 例如:

sophus/so3.hpp:

  /// Returns copy of instance casted to NewScalarType.
  template <class NewScalarType>
  SOPHUS_FUNC SO3<NewScalarType> cast() const {
    return SO3<NewScalarType>(unit_quaternion().template cast<NewScalarType>());
  }

通过 unit_quaternion() 函数获取到内部的单位四元数, 然后通过 template cast转换为新类型

  • C++ template cast

    这里有一个问题:代码中做类型转换的cast前,为什么要加 template修饰?
    先来看所调用的unit_quaternion()函数的代码:

      SOPHUS_FUNC QuaternionType const& unit_quaternion() const {
          return static_cast<Derived const*>(this)->unit_quaternion();
      }
    

    可知其返回的是继承类比如 SO3 内部定义的成员变量(类型为四元数):

    QuaternionMember unit_quaternion_;
    

    再查看 QuaternionMember 定义:

      using QuaternionMember = Eigen::Quaternion<Scalar, Options>;
    

    因此可以知道 unit_quaternion_ 的类型是一个模板类Eigen::Quaternion<Scalar, Options> . 因此通过函数unit_quaternion()返回的类型, 在编译期是不知道的。

    如果不加 template 关键字, 则代码中的cast就会被当做是模板类Eigen::Quaternion<Scalar, Options>的一个成员变量, 而cast后面跟着的<NewScalarType>中的<也会被编译期当做小于号, 从而导致编译错误.

    所以对于 templated type/class, 要加上template关键字, 告诉编译器后面跟着的cast 是一个templated method而不是一个成员变量, 让编译器正确识别这部分语法和编译.

  • 备注

    template 关键字不仅仅可以出现在 cast 前面进行修饰, 还可以出现在其他词前面修饰。 无论后面是什么,其基本原理和上面是相同的,都是告知编译器如何处理其后的代码, 若遇到可以进行类比。

    例如在 Sophus 库中求 SE3 类的 Jacobian 时的代码片段中, 就在 head 和 tail前使用了template,如下:

    Vector3<Scalar> const upsilon = upsilon_omega.template head<3>();
    Vector3<Scalar> const omega = upsilon_omega.template tail<3>();
    Matrix3<Scalar> const J = SO3<Scalar>::leftJacobian(omega);