我试图建立一个包在一个适当大的字符数组一堆的类型,并允许访问数据作为单独的输入正确引用类模板。 现在,根据标准,这可能导致严走样违反,所以未定义的行为,正如我们所访问的char[]
通过一个对象,它是与其不兼容的数据。 具体而言,标准规定:
如果一个程序试图通过的以外的以下类型的行为是未定义的一个glvalue访问对象的存储值:
- 动态型的对象,
- 动态对象的类型的CV-合格版本,
- 类似类型(如在4.4定义)的动态类型的对象,
- 一种类型,是有符号或对应的动态对象的类型无符号类型,
- 一个类型在所述签名或对应于动态型的对象的CV-合格版本无符号类型,
- 包括其元件或非静态数据成员之间的上述类型的一个集合体或联合类型(包括递归地,一个元件或子聚集的非静态数据成员或包含联合),
- 一种类型是一个(可能CV修饰)基类型的动态型的对象的,
- 一个
char
或unsigned char
类型。
由于突出圆点的措辞,我想出了以下alias_cast
想法:
#include <iostream>
#include <type_traits>
template <typename T>
T alias_cast(void *p) {
typedef typename std::remove_reference<T>::type BaseType;
union UT {
BaseType t;
};
return reinterpret_cast<UT*>(p)->t;
}
template <typename T, typename U>
class Data {
union {
long align_;
char data_[sizeof(T) + sizeof(U)];
};
public:
Data(T t = T(), U u = U()) { first() = t; second() = u; }
T& first() { return alias_cast<T&>(data_); }
U& second() { return alias_cast<U&>(data_ + sizeof(T)); }
};
int main() {
Data<int, unsigned short> test;
test.first() = 0xdead;
test.second() = 0xbeef;
std::cout << test.first() << ", " << test.second() << "\n";
return 0;
}
(以上测试代码,尤其是Data
类仅仅是思想的简单化向下的示范,所以请不要指出我应该如何使用std::pair
或std::tuple
。该alias_cast
模板还应该扩大到处理简历合格类型和它只能如果对齐要求得到满足安全使用,但我希望这片段是足以证明这个想法。)
这一招用g沉默的警告++(编译时加入g++ -std=c++11 -Wall -Wextra -O2 -fstrict-aliasing -Wstrict-aliasing
),代码工作,但真的是这样讲的一个有效途径编译器跳过基于严格走样优化?
如果它是无效的,那么如何将一个去实现这样一个字符数组基于通用存储类不违反别名规则?
编辑:更换alias_cast
用一个简单reinterpret_cast
是这样的:
T& first() { return reinterpret_cast<T&>(*(data_ + 0)); }
U& second() { return reinterpret_cast<U&>(*(data_ + sizeof(T))); }
产生当与G ++编译以下警告:
aliastest那么1.cpp:在“T和数据::第一()的实例化[用T = INT; U =短无符号整型]':aliastest那么1.cpp:28:16:
从这里需要aliastest那么1.cpp:21:58:警告:提领类型-punned指针将打破严格走样规则[-Wstrict混叠]