使用 typedef 的模板专业化
Template specialization using typedefs
在学习 Vulkan 时,我在 VulkanCookbook 中看到了一些代码。在 VulkanCookbook 中,作者手动编写了导入 Vulkan 函数和 类 的代码。好吧,我一直在慢慢地将它转换为 LunarG 的 Vulkan 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()
{}
有什么好的方法可以解决这个问题,还是我必须重新编写所有示例代码以手动删除对象?如果可能,我想在 32 位下编译。
抱歉,如果在其他地方有人问过这个问题,我找不到它,因为 google 总是出现部分模板和其他不相关的主题。而且我确实理解编译器正在查看 _A 和 _B 的代码的问题,只是将其视为 uint64_t 而不关心它们的命名不同,这导致 DestroyObject 重载用于导致重新定义的相同模板类型错误。
编辑:修复了使用无效命名的代码,因为这实际上不是核心问题。
你几乎是对的...上面的函数 Handler<_A>::DestroyObject(_A object)
和 Handler<_B>::DestroyObject(_B object)
实际上是模板化成员函数的具体实例化。因为作者没有提供此函数的通用版本,所以您在尝试使用 uint32_t 实例化 class 时遇到了问题。简单的解决方法是编写一个 template<> void Handler<uint32_t>::DestroyObject(uint32_t o)
函数。没有更多的上下文,我无法提供更好的建议。
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;
}
上面的工作是这样的:
argument_t
实用程序检查 E
是否为枚举,并为其提供基础类型。否则它会退回到 E
本身。
主模板接受 T
,并根据需要转换参数。
由于 A
和 B
现在是 不同的 类型,您可以专注于每个类型。该函数接受基础类型作为参数。
模板无法区分作为类型参数传递的 A
和 B
。
可能有手动清理对象的替代方法,但您的问题过于模糊,并且侧重于找到一种方法来让不可行的 solition 工作以确定您的问题到底是什么。
可能您必须使用与类型本身不同的东西来区分类型。
在学习 Vulkan 时,我在 VulkanCookbook 中看到了一些代码。在 VulkanCookbook 中,作者手动编写了导入 Vulkan 函数和 类 的代码。好吧,我一直在慢慢地将它转换为 LunarG 的 Vulkan 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()
{}
有什么好的方法可以解决这个问题,还是我必须重新编写所有示例代码以手动删除对象?如果可能,我想在 32 位下编译。
抱歉,如果在其他地方有人问过这个问题,我找不到它,因为 google 总是出现部分模板和其他不相关的主题。而且我确实理解编译器正在查看 _A 和 _B 的代码的问题,只是将其视为 uint64_t 而不关心它们的命名不同,这导致 DestroyObject 重载用于导致重新定义的相同模板类型错误。
编辑:修复了使用无效命名的代码,因为这实际上不是核心问题。
你几乎是对的...上面的函数 Handler<_A>::DestroyObject(_A object)
和 Handler<_B>::DestroyObject(_B object)
实际上是模板化成员函数的具体实例化。因为作者没有提供此函数的通用版本,所以您在尝试使用 uint32_t 实例化 class 时遇到了问题。简单的解决方法是编写一个 template<> void Handler<uint32_t>::DestroyObject(uint32_t o)
函数。没有更多的上下文,我无法提供更好的建议。
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;
}
上面的工作是这样的:
argument_t
实用程序检查E
是否为枚举,并为其提供基础类型。否则它会退回到E
本身。主模板接受
T
,并根据需要转换参数。由于
A
和B
现在是 不同的 类型,您可以专注于每个类型。该函数接受基础类型作为参数。
模板无法区分作为类型参数传递的 A
和 B
。
可能有手动清理对象的替代方法,但您的问题过于模糊,并且侧重于找到一种方法来让不可行的 solition 工作以确定您的问题到底是什么。
可能您必须使用与类型本身不同的东西来区分类型。