C++中能否定义wrap256_t*到__m256i*的隐式指针转换?
不存在自定义两个原生指针类型间隐式转换的方法。
C++中自定义类型转换规则(转换构造函数、operator转换运算符)仅能作用于自定义类/结构体类型,内置原生指针的转换规则由语言标准固定,无法通过用户代码扩展。你期望的wrap256_t*到__m256i*的隐式原生指针转换,没有任何标准语法可以实现。
以下方案在开启编译优化后,生成的机器码和手动写reinterpret_cast完全一致,无任何性能损失,同时可以避免重复书写类型转换代码:
方案1:重载wrap256_t的取地址运算符
直接重载结构体的operator&,让取地址操作直接返回符合intrinsic要求的__m256i*类型:
struct wrap256_t { alignas(32) uint64_t u64[4]; wrap256_t(uint64_t a, uint64_t b, uint64_t c, uint64_t d) : u64{ a, b, c, d } {} wrap256_t() {} __m256i* operator&() noexcept { return reinterpret_cast<__m256i*>(this); } const __m256i* operator&() const noexcept { return reinterpret_cast<const __m256i*>(this); } };
使用时直接传参即可,无需额外转换:
wrap256_t arr[1024]; __m256i vec = _mm256_load_si256(&arr[0]); _mm256_store_si256(&arr[1], vec);
注意:该方案会修改&运算符的返回值类型,如果代码中存在wrap256_t* p = &obj;这类需要拿到原结构体指针的场景,请使用std::addressof(obj)获取真实的结构体指针,它会绕过自定义的运算符重载。
方案2:封装轻量内联load/store函数(侵入性最低,最推荐)
不需要修改原有结构体定义,直接写两个全局内联函数封装转换和intrinsic调用:
inline __m256i mm256_load(const wrap256_t& src) noexcept { return _mm256_load_si256(reinterpret_cast<const __m256i*>(&src)); } inline void mm256_store(wrap256_t& dst, __m256i val) noexcept { _mm256_store_si256(reinterpret_cast<__m256i*>(&dst), val); }
使用方式更简洁,完全不需要关心指针转换:
wrap256_t a(1,2,3,4), b; __m256i v = mm256_load(a); mm256_store(b, v);
该方案不会影响原有结构体的任何行为,适合代码量较大、已经存在大量wrap256_t指针操作的项目。
不要尝试通过让wrap256_t继承__m256i的方式实现指针转换:__m256i是编译器内置的向量类型,不是可继承的类类型,且该方式会在数组访问、指针偏移场景下引入难以排查的未定义行为。
你的wrap256_t已经声明了32字节对齐,和__m256i的内存对齐要求完全匹配,上述方案中的reinterpret_cast行为在所有支持AVX2的主流编译器(GCC、Clang、MSVC)下都是合法可靠的,不存在内存访问风险。
内容的提问来源于stack exchange,提问作者user81993

