是将std :: pair <T1,T2> const&转换为std :: pair <T1 const,T2> const&safe?

Meh*_*dad 15 c++ templates casting const reinterpret-cast

它是安全的(在理论上还是在实践中),以reinterpret_caststd::pair<T1, T2> const &std::pair<T1 const, T2> const &,假设程序员没有故意做了一些奇怪的类似专业std::pair<T1 const, T2>

eca*_*mur 6

pair 在标准的第 20.3.2 节中定义为具有数据成员:

template <class T1, class T2>
struct pair {
    T1 first;
    T2 second;
};
Run Code Online (Sandbox Code Playgroud)

这意味着,对于具体类型T1T2pair<T1, T2>pair<const T1, T2>保证具有相应的数据成员:

struct pair<T1, T2> {
    T1 first;
    T2 second;
};
struct pair<const T1, T2> {
    const T1 first;
    T2 second;
};
Run Code Online (Sandbox Code Playgroud)

现在,如果T1T2都是标准布局,那么pair<T1, T2>pair<const T1, T2>都是标准布局。如上所述,在DR1334 中,它们与布局不兼容(3.9p11),但在 9.2p19 中,它们可以是reinterpret_cast各自的T1const T1第一个成员。到 9.2p13,T2第二个成员必须位于第一个成员之后(即具有更高的地址),到 1.8p5 必须紧跟在第一个成员之后,以便对象在考虑对齐后是连续的(9.2p19)。

我们可以使用offsetof(这是为标准布局类型定义的)来检查这一点:

static_assert(offsetof(pair<T1, T2>, second) ==
    offsetof(pair<const T1, T2>, second), "!");
Run Code Online (Sandbox Code Playgroud)

由于pair<T1, T2>pair<const T1, T2>具有相同的布局,向前投射并使用结果访问成员对 3.9.2p3 有效:

如果类型的对象T位于 address A,则认为其值为地址的cv 类型的指针指向该对象,而不管该值是如何获得的。T*A

所以reinterpret_cast只有当std::is_standard_layout<std::pair<T1, T2>>::value是 时才是安全的true

  • 您是否看到 Potatoswatter 的评论和有关该问题的链接缺陷报告,断言“T1”和“const T1”实际上与布局不兼容?我不确定我是否同意这个论点,但是您需要一些证据来支持您声称它们与布局兼容的说法。 (2认同)

Ben*_*igt 6

这样做并不便携.

std::pair要求见第20.3条.第17.5.2.3条澄清了这一点

第18至30条及附件D并未指明类别的表示,故意省略类别成员的说明.实现可以根据需要定义静态或非静态类成员或两者,以实现第18至30条和附录D中指定的成员函数的语义.

这意味着实现包括部分专业化是合法的(尽管极不可能),例如:

template<typename T1, typename T2>
struct pair<T1, T2>
{
    T1 first;
    T2 second;
};

template<typename T1, typename T2>
struct pair<const T1, T2>
{
    T2 second;
    const T1 first;
};
Run Code Online (Sandbox Code Playgroud)

显然不是布局兼容的.其他变体包括可能在规则之前first和/或second也允许包含额外的非静态数据成员.


现在,考虑布局已知的情况有点有趣.虽然Potatoswatter指出DR1334断言T并且const T兼容布局,但标准提供了足够的保证,使我们无论如何都可以获得大部分:

template<typename T1, typename T2>
struct mypair<T1, T2>
{
    T1 first;
    T2 second;
};

mypair<int, double> pair1;
mypair<int, double>* p1 = &pair1;
int* p2 = reinterpret_cast<int*>(p1); // legal by 9.2p20
const int* p3 = p2;
mypair<const int, double>* p4 = reinterpret_cast<mypair<const int, double>*>(p3); // again 9.2p20
Run Code Online (Sandbox Code Playgroud)

但是这不起作用,std::pair因为我们无法在不知道first实际上是未指定的初始成员的情况下应用9.2p20 .