直接访问唯一 class 数据成员

Direct access to unique class data member

我有一个 class,它有一个唯一的 public 数据成员,它是一个内置类型:

class foo {
public:
    int data;

    foo(int dataIn) : data(dataIn) {}
    virtual ~foo() {}

    // Some other class methods
protected:
    // Some internal helper class methods
};

在另一个class中,我想使用memcpy方法:

template<typename T>class bar {
protected:
    T data;
public:
    bar() {}
    virtual ~bar() {}

    void read(unsigned char* readBuff, const std::size_t &readSize) {
        // Some stuff
        std::memcpy(readBuff, &(this->data), readSize);
        // Some stuff
    }
};

想法是 barT 是内置类型或 foo 的实例时可用。

但是 T 是 foo,因此 bar 中的 data 是一个 foo 实例,我是否确保从 &(this->data) 指向的元素读取将 datafoo?

当我运行这个:

foo x(12);
std::cout << sizeof(foo);

我得到4,所以foo好像正好是一个int的大小,所以我自然会认为直接reading/writing到x即使不指定x.data 会写入数据。是真的吗?

我需要与 C++11 兼容。

没有

对于带有虚函数的class,通常编译器会在class的开头插入一些元数据。您不能假定实例的地址也是其第一个成员的地址。

你可以用if constexpr来区分这2种情况:

    if constexpr ( std::is_same_v<std::decay_t<T>, foo> ) {
        std::memcpy(readBuff, &(this->data.data), readSize);
    } else {
        std::memcpy(readBuff, &(this->data), readSize);
    }

没有

具有虚拟成员的任意类型的布局是实现定义的。不能保证 data 在 foo.

的偏移量为 0 处

您可以将 bar 完全专门化为 foo

template<>class bar<foo> {
protected:
    foo data;
public:
    bar() {}
    virtual ~bar() {}

    void write(unsigned char* readBuff, const std::size_t &readSize) {
        // Some stuff
        std::memcpy(readBuff, &(this->data.data), readSize);
        // Some stuff
    }
};

如果bar其余部分的重复有问题,你可以写一个辅助模板

template<typename T> bar_helper
{
    void* operator()(T & data) { return &data; }
}

template<> bar_helper<foo>
{
    void* operator()(foo & data) { return &data.data; }
}

template<typename T>
void bar<T>::write(unsigned char* readBuff, const std::size_t &readSize) {
    // Some stuff
    bar_helper<T> helper;
    std::memcpy(readBuff, helper(this->data), readSize);
    // Some stuff
}

经过几次尝试,我找到了另一种实现它的方法,而不必像@Caleth 的解决方案(虽然非常好)那样在 read() 中实例化一个新的 helper 对象,所以哪个应该更好表现:

class foo {
public:
    int data;

    foo(int dataIn) : data(dataIn) {}
    virtual ~foo() {}

    // Some other class methods
protected:
    // Some internal helper class methods
};

template<bool ISFOO> struct IsFoo_ {
    enum {
        IS_FOO_ = ISFOO
    };
};

template<typename T>class bar {
protected:
    T data;
public:
    bar() {}
    virtual ~bar() {}

    struct CRV {
        enum {
            USES_FOO = std::is_same<T, foo>::value
        };
    };

    void* getCopyable() {
        return getCopyable_<CRV::USES_FOO>();
    }

    void read(unsigned char* readBuff, const std::size_t &readSize) {
        // Some stuff
        std::memcpy(readBuff, this->getCopyable(), readSize);
        // Some stuff
    }

private:
    // Caller method
    template<bool ISFOO> inline void* getCopyable_() {
        return getCopyable_(IsBitVector_<ISFOO>());
    }
    // Generic method
    template<bool ISFOO> inline void* getCopyable_(IsFoo_<ISFOO>) {
        return nullptr;
    }
    // Specializations
    inline void* getCopyable_(IsFoo_<true>) {
        return reinterpret_cast<void*>(&(this->data.data));
    }
    inline void* getCopyable_(IsFoo_<false>) {
        return reinterpret_cast<void*>(&(this->data));
    }
};