CUDA 中的 C++11 别名模板

标签 c++ templates c++11 cuda template-aliases

基本问题是alias templates CUDA编译器支持吗?

我在 Ubuntu 上使用 CUDA 7.5 和 gcc-4.8。我的所有模板类都在头文件中定义,并在编译期间 #include 放入单个翻译单元中。

我有一个简单的 cuda_array 类,它为 std::vector 提供了一个薄包装器。它本质上是 thrust::host_vectorthrust::device_vector 组合的一个非常简单的版本。它的声明是

template <typename T, const size_t N>
class cuda_array {
    std::vector<T> host;
    T *device;
public:
    // lots of type aliases to meet container requirements
    void push() { /* cudaMemcpy(...,H2D); */ }
    void pull() { /* cudaMemcpy(...,D2H); */ }
    // a few others that aren't relevant here
};

为了制作矩阵,我刚刚制作了一个快速模板别名。

template <typename T, const size_t M, const size_t N>
using cuda_matrix = cuda_array<T, M * N>;

我想将我的矩阵 vector 乘法 CUDA 内核映射到重载的 operator* 上,以实现类型安全和易于使用(由调用者来确保 pushpull 被正确调用)。

template <typename T, const size_t rows, const size_t cols>
__global__ void matrix_vector_mul(T *A, T *b, T *result) {
     __shared__ T shared_b[cols];
    // rest of it
}

template <typename T, const size_t M, const size_t N>
__host__ cuda_array<T, M> operator*(cuda_matrix<T, M, N> &m, cuda_array<T, N> &v) {
    cuda_array<T, M> result;
    matrix_vector_mul<T, M, N><<<16, 32>>>(m.device_data(), v.device_data(), result.device_data());
    return result;
}

在我的“main.cpp”中,我有

cuda_matrix<int,16,32> A;
cuda_array<int,32> b;
auto result = A * b;

最后一行抛出错误,提示

error: no operator "*" matches these operands
        operand types are: cuda_matrix<int, 16UL, 32UL> * cuda_array<int, 32UL>

我追查了所有我能想到的模板类型推导错误的常见嫌疑人,但没有任何效果。无奈之下,我将我的 cuda_matrix 别名模板转换为模板类。

template <typename T, const size_t M, const size_t N>
class cuda_matrix : public cuda_array<T, M * N> {};

编译错误消失了!因此看来 CUDA 还不支持别名模板。还是我做了一些我无法弄清楚的愚蠢事情?

最佳答案

你必须记住:

§ 14.5.7 [临时别名]/p2:

When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template. [ Note: An alias template name is never deduced. — end note ]

这意味着不执行扣除:

template <typename T, const size_t M, const size_t N>
__host__ cuda_array<T, M> operator*(cuda_matrix<T, M, N> &m, cuda_array<T, N> &v)

但对于:

template <typename T, const size_t M, const size_t N>
__host__ cuda_array<T, M> operator*(cuda_array<T, M * N> &m, cuda_array<T, N> &v)
//                                  ~~~~~~~~~~~~~~~~~~~^

所以:

§ 14.8.2.5 [temp.deduct.type]/p16:

If, in the declaration of a function template with a non-type template parameter, the non-type template parameter is used in a subexpression in the function parameter list, the expression is a non-deduced context as specified above.

M 处于不可推导的上下文中,因此此operator* 不被视为可行的重载。

作为解决方法之一,您可以验证 cuda_array 本身的推导值:

template <typename T, std::size_t MN, std::size_t N>
auto operator*(const cuda_array<T, MN>& m, const cuda_array<T, N>& v)
    -> typename std::enable_if<(MN/N)*N==MN, cuda_array<T, MN/N>>::type;

或者使用你已有的继承技巧;那么 MNcuda_matrix 的独立非类型模板参数。

关于CUDA 中的 C++11 别名模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33010352/

相关文章:

C++:返回变量的地址?我如何让这个字符串返回,然后将一个小字符串连接到它上面?

c++ - 如何制作一个值超过允许的最大整数的枚举?

C++ 组合模板扩展

c++ - QList 内部函数模板

c++ - Apple LLVM 4.2 段错误使用基于范围的循环和引用

c++ - 查找 cpp_int 二进制长度的简单方法

c++ - BOOST::Gil 用于图像处理

c++ - clang 不编译我的代码,但 g++ 可以

c++ - 为什么我要 std::move 一个 std::shared_ptr?

c++ - 在 std::enable_if 中使用 sizeof...