使用 typedef 的模板特化

Cie*_*ric 4 c++ templates typedef vulkan

在学习 Vulkan 时,我在 VulkanCookbook 中遇到了一些代码。在 VulkanCookbook 中,作者编写了手动导入 Vulkan 函数和类的代码。好吧,我一直在慢慢地将它转换为 Vulkan 的 LunarG SDK,我在 64 位 VkFence 下遇到了一个问题,它 typedef 到 VkFence_T* 这很好,但在 32 位中它被 typedef 为 uint64_t,这会导致VkDestroyer 使用类似于下面的代码的问题

#include <iostream>
#include <stdint.h>

typedef uint64_t A;
typedef uint64_t B;

template<typename T>
class Handler
{
    void DestroyObject( T parent );
};

template<>
inline void Handler<A>::DestroyObject(A object) {
  std::cout << "destroy type A" << std::endl;
}

template<>
inline void Handler<B>::DestroyObject(B object) {
  std::cout << "destroy type B!" << std::endl;
}

int main()
{}
Run Code Online (Sandbox Code Playgroud)

有什么好的方法可以解决这个问题,还是我必须重新编写所有示例代码以手动删除对象?如果可能,我想在 32 位下编译。

抱歉,如果在其他地方问过这个问题,我找不到它,因为 google 总是会出现部分模板和其他不相关的主题。而且我确实理解编译器正在查看 _A 和 _B 的代码的问题,并且只是将其视为 uint64_t 而不关心它们的名称不同,这会导致 DestroyObject 重载针对相同的模板类型,从而导致重新定义错误。

编辑:使用无效命名修复代码,因为这实际上不是核心问题。

Sto*_*ica 5

C++ 没有强类型定义。类型别名只是现有类型的另一个名称,在使用时完全等同于它的别名类型。

您需要A和B成为实际类型,而不是别名,它们都与uint64_t. 只要您将自己限制在整数类型,您就可以从中构建新的不同类型。

解决方案是使用为其指定基础类型的枚举。

#include <type_traits>

template<typename E>
using argument_t = std::conditional_t<std::is_enum<E>::value,
                                      std::underlying_type_t<E>,
                                      E>; 

template<typename T>
class Handler
{
    void DestroyObject( argument_t<T> parent );
};

enum A : uint64_t {};
enum B : uint64_t {}; 

template<>
inline void Handler<A>::DestroyObject(uint64_t object) {
  std::cout << "destroy type A" << std::endl;
}

template<>
inline void Handler<B>::DestroyObject(uint64_t object) {
  std::cout << "destroy type B!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

上面的工作是这样的:

  • 该argument_t实用程序检查是否E为枚举,并为其提供基础类型。否则它会退回到E它自己。

  • 主模板接受 a T,并在需要时转换参数。

  • 由于A和现在B是不同的类型,您可以专注于每个类型。该函数接受基础类型作为参数。