让非CUDA代码在可使用std函数的CUDA环境中仍能与CUDA兼容(前提是存在cuda::std)

编程语言 2026-07-11

我正在尝试创建一个函数,用于将float/double/float16进行按位转换,得到等大小的无符号整型值。我可以在主机端代码中很容易实现,示例如下:

template<std::floating_point T>
[[nodiscard]]
constexpr auto bit_cast_unsigned(T t) {
    if constexpr(sizeof(T) == 1) {
        return std::bit_cast<std::uint8_t>(t);
    }
    if constexpr(sizeof(T) == 2) {
        return std::bit_cast<std::uint16_t>(t);
    }
    if constexpr(sizeof(T) == 4) {
        return std::bit_cast<std::uint32_t>(t);
    }
    if constexpr(sizeof(T) == 8) {
        return std::bit_cast<std::uint64_t>(t);
    }

}

然而,我也希望能够在设备端代码中支持这个功能,并且希望这个函数在运行时即可使用,而不仅仅在编译时可用,我需要执行以下操作:

template<std::floating_point T>
[[nodiscard]]
__host__ __device__ 
constexpr auto bit_cast_unsigned(T t) {
    if constexpr(sizeof(T) == 1) {
        return cuda::std::bit_cast<std::uint8_t>(t);
    }
    if constexpr(sizeof(T) == 2) {
        return cuda::std::bit_cast<std::uint16_t>(t);
    }
    if constexpr(sizeof(T) == 4) {
        return cuda::std::bit_cast<std::uint32_t>(t);
    }
    if constexpr(sizeof(T) == 8) {
        return cuda::std::bit_cast<std::uint64_t>(t);
    }

}

问题在于,当我所处的代码库不使用CUDA时,这种做法就不起作用,我也不想让CUDA成为这个函数存在的前提条件。但我仍然希望在可用时支持与 cuda::std:: 等价的函数。

有没有类似这样的做法:

#if defined(CUDA_ENABLED)
#include <cuda/bit> 
#define PROJECT_HOST_DEVICE_STD_NAMESPACE cuda::std
#define PROJECT_HOST_DEVICE __host__ __device__
#else
#include <bit> 
#define PROJECT_HOST_DEVICE_STD_NAMESPACE std
#define PROJECT_HOST_DEVICE
#endif

...


template<std::floating_point T>
[[nodiscard]]
PROJECT_HOST_DEVICE
constexpr auto bit_cast_unsigned(T t) {
    if constexpr(sizeof(T) == 1) {
        return PROJECT_HOST_DEVICE_STD_NAMESPACE::bit_cast<std::uint8_t>(t);
    }
    if constexpr(sizeof(T) == 2) {
        return PROJECT_HOST_DEVICE_STD_NAMESPACE::bit_cast<std::uint16_t>(t);
    }
    if constexpr(sizeof(T) == 4) {
        return PROJECT_HOST_DEVICE_STD_NAMESPACE::bit_cast<std::uint32_t>(t);
    }
    if constexpr(sizeof(T) == 8) {
        return PROJECT_HOST_DEVICE_STD_NAMESPACE::bit_cast<std::uint64_t>(t);
    }

}

我看过类似的帖子,例如 CUDA和 nvcc: using the preprocessor to choose between float or double,似乎指示使用 __CUDACC__ 作为一种解决方案,然而我担心如果在没有CUDA的代码库中,有一个cpp文件中的某段代码使用 bit_cast_unsigned 编译(例如通过VCPKG间接传递),然后另一段代码,位于另一个启用CUDA的库中,或最终启用CUDA的可执行文件中使用相同的 bit_cast_unsigned,可能会遇到怪异的链接器问题之类的情况。

我能像上面那样在CUDA与非CUDA的代码库中使用 __CUDACC__ 而不出问题吗(它们甚至可能混合在一起,如在VCPKG中那样),还是有其他解决方案?

解决方案

作为起点,我会使用命名空间别名来替代宏:

#if defined(CUDA_ENABLED)
#include <cuda/bit> 
namespace host_device = cuda::std;
#else
#include <bit> 
namespace host_device = std;
#endif

[ ...]

    if constexpr(sizeof(T) == 1) {
        return host_device::bit_cast<std::uint8_t>(t);
    }
    if constexpr(sizeof(T) == 2) {
        return host_device::bit_cast<std::uint16_t>(t);
    }
    if constexpr(sizeof(T) == 4) {
        return host_device::bit_cast<std::uint32_t>(t);
    }
    if constexpr(sizeof(T) == 8) {
        return host_device::bit_cast<std::uint64_t>(t);
    }
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章