问题描述
下面的代码是尝试在C ++ 11中实现offsetof
的constexpr
版本的尝试.它可以在gcc 7.2.0和clang 5.0.0中进行编译.
The code below is an attempt at implementing a constexpr
version of offsetof
in C++11. It compiles in both gcc 7.2.0 and clang 5.0.0.
这取决于将std::addressof
应用于工会的非活跃成员.
It depends on applying std::addressof
to members of non-active members of a union.
这是定义良好的C ++ 11吗?如果不是,请说明原因,包括对标准相关部分的引用或引用.
Is this well-defined C++11? If not, please explain why, including quotes or citations to relevant sections of the standard.
#include <iostream>
#include <cstdint>
#include <memory>
// based on the gist at: https://gist.github.com/graphitemaster/494f21190bb2c63c5516
// original version by graphitemaster
template <typename T1, typename T2>
struct offset_of_impl {
union U {
char c;
T1 m; // instance of type of member
T2 object;
constexpr U() : c(0) {} // make c the active member
};
static constexpr U u = {};
static constexpr std::ptrdiff_t offset(T1 T2::*member) {
// The following avoids use of reinterpret_cast, so is constexpr.
// The subtraction gives the correct offset because the union layout rules guarantee that all
// union members have the same starting address.
// On the other hand, it will break if object.*member is not aligned.
// Possible problem: it uses std::addressof on non-active union members.
// Please let us know at the gist if this is defined or undefined behavior.
return (std::addressof(offset_of_impl<T1, T2>::u.object.*member) -
std::addressof(offset_of_impl<T1, T2>::u.m)) * sizeof(T1);
}
};
template <typename T1, typename T2>
constexpr typename offset_of_impl<T1, T2>::U offset_of_impl<T1, T2>::u;
template <typename T1, typename T2>
inline constexpr std::ptrdiff_t offset_of(T1 T2::*member) {
return offset_of_impl<T1, T2>::offset(member);
}
struct S {
S(int a_, int b_, int c_) : a(a_), b(b_), c(c_) {}
S() = delete;
int a;
int b;
int c;
};
int main()
{
std::cout << offset_of(&S::b);
}
作为参考,这是一个可以使用的沙盒版本: https://wandbox.org/permlink/rKQXopsltQ51VtEm
For reference, here is a sandbox version to play with: https://wandbox.org/permlink/rKQXopsltQ51VtEm
这是石墨大师的原始版本: https://gist.github.com/graphitemaster/494f21190bb2c63c5516
And here is the original version by graphitemaster:https://gist.github.com/graphitemaster/494f21190bb2c63c5516
推荐答案
union U { int a; int b; };
U u;
u.a = 0; // (1)
int* pub = &u.b;
是的,这个定义很好,但是使用pub
的方式受到限制.注意:使用运算符&
或std::addressof
获取对象的地址类似于,除非为该对象的类型定义了自定义运算符&
.
Yes, this is well defined, but there is restrictions on the way one can use pub
. Note : taking the address of an object with the operator &
or with std::addressof
is similar unless a custom operator &
is defined for that object's type.
因此在标记为(1)
的行上,u.b
的生存期尚未开始,但是已分配了该对象将占用的存储空间.正在关注:
So on line marked (1)
, the lifetime of u.b
has not started yet, but the storage that object will occupy has been allocated. Following :
就像用户Quentin指出的那样,它将绑定对u.b
的引用,但是按照 [basic.life]/7
:
Except it would, as user Quentin noted, bind a reference to u.b
, but it's also OK as per [basic.life]/7
:
这篇关于在非活动工会成员上使用`std :: addressof`是否定义明确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!