我有一个具有唯一公共数据成员的类,它是一个内置类型:
class foo {
public:
int data;
foo(int dataIn) : data(dataIn) {}
virtual ~foo() {}
// Some other class methods
protected:
// Some internal helper class methods
};
在其他课程中,我想使用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
}
};
如果bar
是内置类型或T
的实例,则foo
可以使用{/ 1}}。
但是,foo
data
实例中的T是bar
,因此是foo
,我确保从&(this->data)
指向的元素中读取data
中的foo
?
当我运行时:
foo x(12);
std::cout << sizeof(foo);
我得到4
,所以foo似乎正好是int的大小,所以我自然会认为直接读/写x
即使没有指定x.data
也会写入数据。这是真的吗?
我需要兼容C ++ 11。
答案 0 :(得分:4)
没有
对于具有虚函数的类,通常编译器会在类的开头插入一些元数据。您不能假设实例的地址也是其第一个成员的地址。
您可以使用if constexpr
区分这两种情况:
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);
}
答案 1 :(得分:3)
没有
具有虚拟成员的任意类型的布局是实现定义的。您无法保证在foo中偏移量为data
。
您可以为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
}
答案 2 :(得分:0)
经过多次尝试,我发现了另一种实现它的方法,而不必像在@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));
}
};