【发布时间】:2016-09-08 02:31:51
【问题描述】:
第一个类将用于私有继承,以确保完全相同的布局。这应该可以确保投射安全。
#include <iostream>
#include <string>
struct data_base
{
data_base( int i, std::string&& s ) noexcept
: i_{ i }
, s_{ std::move( s ) }
{}
int i_;
std::string s_;
};
在这个简单的示例中,我首先打印int 数据成员,然后是std::string 数据成员,用于data<true> 的实例。
template<bool = true>
struct data : private data_base // inherits
{
data( int i, std::string&& s ) noexcept
: data_base( i, std::move( s ) )
{}
void print()
{
std::cout << "data<true> - " << i_ << s_ << '\n';
}
};
但是,data<false> 首先打印 std::string 数据成员,然后是 int 数据成员。
template<>
struct data<false> : private data_base
{
void print()
{
std::cout << "data<false> - " << s_ << i_ << '\n';
}
};
例子:
int main()
{
data<true> d{ 5, "abc" };
d.print();
( ( data<false>& )d ).print();
}
演示:http://coliru.stacked-crooked.com/a/8b1262afe23dc0a2
如演示所示,即使打开-fstrict-aliasing 标志,也不会出现警告。
现在,由于它们具有相同的布局,我认为我可以在这两种类型之间进行转换以获得不同类型的静态多态性;无需虚函数调用。
这种用法安全还是我触发了未定义的行为?
【问题讨论】:
-
不确定
std::string是否保证是标准布局类 -
我认为出于严格别名规则的目的,
print调用算作“使用存储的值”,但不是 100% 确定 -
严格来说,无关类型之间的任何强制转换都会导致未定义的行为。此外,在 C++ 中,建议使用 C++ 类型转换操作符而不是 C 风格类型转换。
-
@antred 在指针或对不相关类型的引用之间进行转换肯定不是 UB。问题出现在引用对象的某些用途中。参见 C++14 [expr.reinterpret.cast]/7。即使是未对齐的强制转换也是未指定(从 C++14 开始),而不是像在 C 中那样未定义。
标签: c++ performance casting type-conversion language-lawyer