The member function of mlir::detail::StorageUserTraitBase< ConcreteType, TraitType >

//===----------------------------------------------------------------------===//
// StorageUserTraitBase
//===----------------------------------------------------------------------===//

/// Helper class for implementing traits for storage classes. Clients are not
/// expected to interact with this directly, so its members are all protected.
template <typename ConcreteType, template <typename> class TraitType>
class StorageUserTraitBase {
protected:
  /// Return the derived instance.
  ConcreteType getInstance() const {
    // We have to cast up to the trait type, then to the concrete type because
    // the concrete type will multiply derive from the (content free) TraitBase
    // class, and we need to be able to disambiguate the path for the C++
    // compiler.
    auto *trait = static_cast<const TraitType<ConcreteType> *>(this);
    return *static_cast<const ConcreteType *>(trait);
  }
};

Hello, I read the code of “mlir::detail::StorageUserTraitBase< ConcreteType, TraitType >”. I find the comment of “getInstance()”. Here say “the concrete type will multiply derive from the TraitBase”. So must call statatic_cast two times. Is there any related samples? I think the StorageUserTraitBase is the templace, In different trait, the templace parameter is different. The corresponding StorageUserTraitBase class is different. So, I think here don’t need call statatic_cast two times.

Please tell me if my understanding is right or wrong.

Thanks!