Шаблоны псевдонимов C++11 в CUDA
Основной вопрос в том, поддерживаются ли шаблоны псевдонимов компилятором CUDA?
Я использую CUDA 7.5 на Ubuntu с gcc-4.8. Все мои классы шаблонов определены в заголовочных файлах и #include
г в одну единицу перевода во время компиляции.
У меня простой cuda_array
класс, который обеспечивает тонкую обертку вокруг std::vector
, По сути, это очень простая версия thrust::host_vector
в сочетании с thrust::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>;
Я хочу отобразить свое ядро CUDA умножения матрицы на вектор на перегруженный operator*
для обеспечения безопасности и простоты использования (вызывающий абонент должен убедиться, что push
а также pull
называются правильно).
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 еще не поддерживает шаблоны псевдонимов. Или я сделал глупость, которую не могу понять?
1 ответ
Вы должны помнить, что:
§ 14.5.7 [temp.alias] / p2:
Когда идентификатор шаблона ссылается на специализацию шаблона псевдонима, он эквивалентен связанному типу, полученному путем подстановки его аргументов шаблона для параметров шаблона в идентификаторе типа шаблона псевдонима. [ Примечание: имя шаблона псевдонима никогда не выводится. - конец примечания ]
Это означает, что вычет не выполняется для:
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:
Если в объявлении шаблона функции с параметром шаблона нетипичного типа параметр шаблона нетипичного типа используется в подвыражении в списке параметров функции, то выражение является не выведенным контекстом, как указано выше.
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;
или используйте трюк наследования, который у вас уже есть; затем M
а также N
являются отдельными типовыми параметрами шаблона cuda_matrix
,