我有一个表示二进制消息的结构.我想编写一个函数来从缓冲区(无论是文件还是套接字,无关紧要)获取下一个这样的记录:
template <typename Record>
Record getNext();
Run Code Online (Sandbox Code Playgroud)
现在,我可以这样写:
template <typename Record>
Record getNext() {
Record r;
populateNext(reinterpret_cast<char*>(&r), // maybe ::read()
sizeof(r)); // or equivalent
return r;
}
Run Code Online (Sandbox Code Playgroud)
这很好,给了我RVO的好处.但是,它将调用默认构造函数Record,该构造函数可以由具有非trival默认构造函数的类型组成,这些构造函数可以工作,我希望避免这些 - 这些不一定是POD类型,但它们是标准布局.
有没有办法写getNext()这样我们避免任何构造函数(默认或复制/移动)Record?理想情况下,当用户调用时:
auto record = getNext<Record>();
Run Code Online (Sandbox Code Playgroud)
缓冲区直接读入内存record.这可能吗?
no_init是类型的常量no_init_t.
如果你从a构造一个pod no_init_t,你得到一个未初始化的pod,并且(假设是elision)没有什么可以做的.
如果从a构造非pod no_init_t,则必须覆盖构造函数,并使其不初始化数据.通常class_name(no_init_t):field1(no_init), field2(no_init){}会这样做,有时class_name(no_init_t){}也会这样做(假设所有内容都是pod).
no_init然而,从每个成员构建可以充当理智检查成员确实是pod.构造的非pod类no_init将无法编译,直到您编写no_init_t构造函数.
这(对no_init每个成员构造函数)确实会产生一些恼人的DRY失败,但我们没有反思,所以你会重复自己并喜欢它.
namespace {
struct no_init_t {
template<class T, class=std::enable_if_t<std::is_pod<T>{}>>
operator T()const{
T tmp;
return tmp;
}
static no_init_t instance() { return {}; }
no_init_t(no_init_t const&) = default;
private:
no_init_t() = default;
};
static const no_init = no_init_t::instance();
}
struct Foo {
char buff[1000];
size_t hash;
Foo():Foo(""){}
template<size_t N, class=std::enable_if_t< (N<=sizeof(buff)) >>
Foo( char const(&in)[N] ) {
// some "expensive" copy and hash
}
Foo(no_init_t) {} // no initialization!
};
struct Record {
int x;
Foo foo;
Record()=default;
Record(no_init_t):
x(no_init), foo(no_init)
{}
};
Run Code Online (Sandbox Code Playgroud)
现在我们可以构造Record,no_init它不会被初始化.
每个POD类都没有初始化.每个非POD类都必须提供一个no_init_t构造函数(并且可能会尽可能地实现非初始化).
然后你就memcpy可以了.
这需要修改您的类型及其包含的类型,以支持非初始化.
| 归档时间: |
|
| 查看次数: |
361 次 |
| 最近记录: |