本文介绍了在非活动工会成员上使用`std :: addressof`是否定义明确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码是尝试在C ++ 11中实现offsetofconstexpr版本的尝试.它可以在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`是否定义明确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 14:54