推力减少和重载运算符-(const float3& ;, const float3&)不会编译 [英] Thrust reduction and overloaded operator-(const float3&, const float3&) won't compile
问题描述
我重载了运算符,使vectorspace.cuh
中的float3
(和类似结构)上的向量空间为:
I overload operators to have a vector space over float3
(and similar structs) in vectorspace.cuh
:
// Boilerplate vector space over data type Pt
#pragma once
#include <type_traits>
// float3
__device__ __host__ float3 operator+=(float3& a, const float3& b) {
a.x += b.x; a.y += b.y; a.z += b.z;
return a;
}
__device__ __host__ float3 operator*=(float3& a, const float b) {
a.x *= b; a.y *= b; a.z *= b;
return a;
}
// float4
__device__ __host__ float4 operator+=(float4& a, const float4& b) {
a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w;
return a;
}
__device__ __host__ float4 operator*=(float4& a, const float b) {
a.x *= b; a.y *= b; a.z *= b; a.w *= b;
return a;
}
// Generalize += and *= to +, -=, -, *, /= and /
template<typename Pt> __device__ __host__
typename std::enable_if<std::is_class<Pt>::value || std::is_enum<Pt>::value, Pt>::type
operator+(const Pt& a, const Pt& b) {
auto sum = a;
sum += b;
return sum;
}
template<typename Pt> __device__ __host__
typename std::enable_if<std::is_class<Pt>::value || std::is_enum<Pt>::value, Pt>::type
operator-=(Pt& a, const Pt& b) {
a += -1*b;
return a;
}
template<typename Pt> __device__ __host__
typename std::enable_if<std::is_class<Pt>::value || std::is_enum<Pt>::value, Pt>::type
operator-(const Pt& a, const Pt& b) {
auto diff = a;
diff -= b;
return diff;
}
template<typename Pt> __device__ __host__
typename std::enable_if<std::is_class<Pt>::value || std::is_enum<Pt>::value, Pt>::type
operator-(const Pt& a) {
return -1*a;
}
template<typename Pt> __device__ __host__
typename std::enable_if<std::is_class<Pt>::value || std::is_enum<Pt>::value, Pt>::type
operator*(const Pt& a, const float b) {
auto prod = a;
prod *= b;
return prod;
}
template<typename Pt> __device__ __host__
typename std::enable_if<std::is_class<Pt>::value || std::is_enum<Pt>::value, Pt>::type
operator*(const float b, const Pt& a) {
auto prod = a;
prod *= b;
return prod;
}
template<typename Pt> __device__ __host__
typename std::enable_if<std::is_class<Pt>::value || std::is_enum<Pt>::value, Pt>::type
operator/=(Pt& a, const float b) {
a *= 1./b;
return a;
}
template<typename Pt> __device__ __host__
typename std::enable_if<std::is_class<Pt>::value || std::is_enum<Pt>::value, Pt>::type
operator/(const Pt& a, const float b) {
auto quot = a;
quot /= b;
return quot;
}
这些重载中断了thrust::reduce
的编译,这里是一个示例:
These overloads break compilation of thrust::reduce
, here an example:
#include <thrust/reduce.h>
#include <thrust/execution_policy.h>
#include "vectorspace.cuh"
int main(int argc, char const *argv[]) {
int n = 10;
float3* d_arr;
cudaMalloc(&d_arr, n*sizeof(float3));
auto sum = thrust::reduce(thrust::device, d_arr, d_arr + n, float3 {0});
return 0;
}
在Ubuntu 16.04上使用nvcc -std=c++11 -arch=sm_52
会导致200多行编译器错误:
Using nvcc -std=c++11 -arch=sm_52
on Ubuntu 16.04 this results in 200+ lines of compiler errors:
$ nvcc -std=c++11 -arch=sm_52 sandbox/mean.cu
sandbox/mean.cu(26): error: no operator "*" matches these operands
operand types are: int * const thrust::zip_iterator<thrust::tuple<const float3 *, thrust::pointer<float3, thrust::system::cuda::detail::par_t, thrust::use_default, thrust::use_default>, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type>>
detected during:
instantiation of "std::enable_if<<expression>, Pt>::type operator-=(Pt &, const Pt &) [with Pt=thrust::zip_iterator<thrust::tuple<const float3 *, thrust::pointer<float3, thrust::system::cuda::detail::par_t, thrust::use_default, thrust::use_default>, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type>>]"
(35): here
instantiation of "std::enable_if<<expression>, Pt>::type operator-(const Pt &, const Pt &) [with Pt=thrust::zip_iterator<thrust::tuple<const float3 *, thrust::pointer<float3, thrust::system::cuda::detail::par_t, thrust::use_default, thrust::use_default>, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type>>]"
...
如何在不破坏thrust
的情况下使运算符超载?
How can I overload the operators without breaking thrust
?
推荐答案
(在OP编辑后编辑.)
问题出在运算符重载的到达"上:您不仅要为您感兴趣的类重载,而且要为符合您的enable_if
条件的 all 类重载-相当放松.即使可以编译,这已经是一个严重的错误.
The problem is with the 'reach' of your operator overloads: You are not overloading only for the classes you're interested in, but for all classes fitting your enable_if
condition - which is quite relaxed. That's already a serious bug even if things would compile.
更具体地说,推力使用算术运算,例如可以理解,在"zip迭代器"上(不管它们是什么),您的操作编译失败.
More specifically, thrust uses arithmetic operations, e.g. on "zip iterators" (never mind what they are), and compilations of your operations for such iterators fails, understandably.
因此您必须:
- 准确指定过载与哪些类相关(例如,在
enable_if
中使用std::is_same
的析取),或 -
使用特征类:
- Specify exactly which classes the overload is relevant to (e.g., using a disjunction of
std::is_same
in theenable_if
), or use a trait class:
template<class T> struct needs_qivs_arithmetic_operators : public std::false_type {};
template<> struct needs_qivs_arithmetic_operators<float3> : public std::true_type {};
template<> struct needs_qivs_arithmetic_operators<float4> : public std::true_type {};
/* ... etc. You can also add specializations elsewhere in the translation unit. */
这篇关于推力减少和重载运算符-(const float3& ;, const float3&)不会编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!