在面向x86-64的Windows上,我们有__unaligned
说明符。 1 2 这很麻烦。我要:1)对其进行编译时测试; 2)在编译时从类型中删除说明符; 3)当我在函数调用的结果中找到它时,将其丢弃。抛弃它恰好需要const_cast
,就像运气一样,所以任何解决方案都可能不会轻易保持const
-ness。
另外,鉴于Windows Shell API中ITEMIDLIST类型(P [C] [U] IDLIST_ABSOLUTE,P [C] [U] IDLIST_RELATIVE ...)的指针驱动性质,将是很高兴将上面的指针与指针一起使用。
如何做到这一点?
这是一个方便的代码示例,可用于:
int main(int, char**)
{
//test that aligned_cast works for non-const pointers
using AType = int __unaligned *;
int a_data = 1;
AType a = &a_data;
auto aa = aligned_cast<int *>(a);
//check that it works for const pointers
using BType = const int __unaligned *;
const int b_data = 2;
BType b = &b_data;
auto *bb = aligned_cast<const int *>(b);
//int *bbb = aligned_cast<int *>(b); <--won't compile, good
//check that remove_aligned really is doing its job
using CType = remove_aligned<AType>::type;
static_assert (is_aligned<CType>::value, "");
//auto aaa = aligned_cast<int **>(&a); <-- &a cannot be passed as a reference
return 0;
}
1)__unaligned
是安腾时代之前一直存在的怪异现象。它隐藏在Windows API中,因此(在Windows上)我们受其困扰。我们通常不使用ITEMIDLIST
,当我们使用#define STRICT_TYPE_ITEMIDS
时,通常要小心行事。问题在于,reinterpret_cast
-那些类型非常令人讨厌(令人讨厌(然后如果需要,const_cast
摆脱__unaligned
说明符)。>
2)编辑:如果您不确信__unaligned
不再适用,在将x86-64定位为目标时,请试一下我对Godbolt的回答,看看它是否编译时不进行强制转换。具体来说,从测试工具中更改以下几行会导致编译失败:
59 //auto aa = aligned_cast<int *>(a);
60 int *aa = a; //nope, a is int __unaligned *
答案 0 :(得分:0)
这是内联说明的可能解决方案。有两个三个警告:
int **foo = aligned_cast<int **>(&bar)
无效(&bar
的结果是右值)。int __unaligned * const
变成int *
)。我尚未对此进行测试,因为我已经为此工作了九个多小时,而且很累。反正
#include <utility>
//remove_all_pointers simply wipes out any pointers so we can get to the raw type (plus its cv-qualifiers)
template <class T>
struct remove_all_pointers { using type = T; };
template <class T>
struct remove_all_pointers<T *> { using type = remove_all_pointers<T>; };
template <class T>
using remove_all_pointers_t = typename remove_all_pointers<T>::type;
//this selector works like is_const, only it catches __unaligned instead
template<class T>
struct is_aligned_helper : std::true_type {};
template<class T>
struct is_aligned_helper<__unaligned T> : std::false_type {};
//wipe all pointers before we check for __unaligned
template<class T , class = std::enable_if<std::is_pointer_v<T>>>
struct is_aligned : is_aligned_helper<remove_all_pointers_t<T>> {};
template<class T>
using is_aligned_v = typename is_aligned<T>::value;
template <class T>
struct remove_aligned_helper { using type = T; };
template <class T>
struct remove_aligned_helper<__unaligned T> { using type = T; };
template <class T>
struct remove_aligned
{
//remove the pointer, remove the __unaligned specifier, then put the pointer back
using type = std::add_pointer_t<
typename remove_aligned_helper<
std::remove_pointer_t<T>>::type>;
};
//we can specialize for pointers to pointers, too
template <class T>
struct remove_aligned<T **> {
using type = std::add_pointer_t<typename remove_aligned<T *>::type>;
};
template <class T>
using remove_aligned_t = typename remove_aligned<T>::type;
template <class To, class From, class = std::enable_if<std::is_pointer<From>() && !is_aligned<From>()>>
constexpr To aligned_cast(From &value) noexcept
{
return reinterpret_cast<To>(const_cast<remove_aligned_t<From>>(value));
}
int main(int, char**)
{
//check that it works at all
using AType = int __unaligned *;
int a_data = 1;
AType a = &a_data;
int * aa = aligned_cast<int *>(a);
(void)aa;
//check that it works for const pointers
using BType = const int __unaligned *;
const int b_data = 2;
BType b = &b_data;
const int *bb = aligned_cast<const int *>(b);
(void)bb;
//int *bbb = aligned_cast<int *>(b); //<--won't compile, good
//check that remove_aligned really is doing its job
using CType = remove_aligned<AType>::type;
static_assert (is_aligned<CType>::value, "");
//check that T** works
AType *d = &a;
int ** aaa = aligned_cast<int **>(d); //<-- &a cannot be passed as a reference
(void)aaa;
}
这里是the code的Godbolt。