std::launder c++17 之前的替代方案
std::launder alternative pre c++17
类似于std::optional
,但不存储额外的布尔值。用户必须确保只有在初始化后才能访问。
template<class T>
union FakeOptional { //Could be a normal struct in which case will need std::aligned storage object.
FakeOptional(){} //Does not construct T
template<class... Args>
void emplace(Args&&... args){
new(&t) T{std::forward<Args&&>(args)...};
}
void reset(){
t.~T();
}
operator bool() const {
return true;
}
constexpr const T* operator->() const {
return std::launder(&t);
}
constexpr T* operator->() {
return std::launder(&t);
}
T t;
};
如果您想知道为什么我需要这样一个晦涩的数据结构,请查看此处:https://gitlab.com/balki/linkedlist/tree/master
问题
- 可以忽略
std::launder
吗?我猜不是。
- 由于
std::launder
只在c++17中可用,如何在c++14中实现上面的class? boost::optional
和 std::experimental::optional
应该需要类似的功能,还是他们使用了编译器特定的魔法?
注意:容易漏掉,类型声明为union
。这意味着 T
的构造函数实际上没有被调用。参考:https://gcc.godbolt.org/z/EVpfSN
不,你不能。提出 std::launder
的原因之一是 std::optional
在 C++14 中不可实现。详情可参考this discussion
另一方面,您可以在没有 constexpr
的情况下实现一个。这个想法是使用带有 reinterpret_cast
的缓冲区,因为 reinterpret_cast
的结果将始终引用新创建的对象(在 C++17 中 std::launder
仍然是必需的,但在 C++14 中这可以)。例如,
template<class T>
struct FakeOptional {
FakeOptional(){}
template<class... Args>
void emplace(Args&&... args){
new(&storage) T{std::forward<Args&&>(args)...};
}
void reset(){
reinterpret_cast<T*>(&storage)->~T();
}
operator bool() const {
return true;
}
const T* operator->() const {
return reinterpret_cast<const T*>(&storage);
}
T* operator->() {
return reinterpret_cast<T*>(&storage);
}
std::aligned_storage_t<sizeof(T), alignof(T)> storage;
};
执行 boost::optional
uses this idea and does not implement constexpr
semantic (you can refer to its source code 了解详情)。
类似于std::optional
,但不存储额外的布尔值。用户必须确保只有在初始化后才能访问。
template<class T>
union FakeOptional { //Could be a normal struct in which case will need std::aligned storage object.
FakeOptional(){} //Does not construct T
template<class... Args>
void emplace(Args&&... args){
new(&t) T{std::forward<Args&&>(args)...};
}
void reset(){
t.~T();
}
operator bool() const {
return true;
}
constexpr const T* operator->() const {
return std::launder(&t);
}
constexpr T* operator->() {
return std::launder(&t);
}
T t;
};
如果您想知道为什么我需要这样一个晦涩的数据结构,请查看此处:https://gitlab.com/balki/linkedlist/tree/master
问题
- 可以忽略
std::launder
吗?我猜不是。 - 由于
std::launder
只在c++17中可用,如何在c++14中实现上面的class?boost::optional
和std::experimental::optional
应该需要类似的功能,还是他们使用了编译器特定的魔法?
注意:容易漏掉,类型声明为union
。这意味着 T
的构造函数实际上没有被调用。参考:https://gcc.godbolt.org/z/EVpfSN
不,你不能。提出 std::launder
的原因之一是 std::optional
在 C++14 中不可实现。详情可参考this discussion
另一方面,您可以在没有 constexpr
的情况下实现一个。这个想法是使用带有 reinterpret_cast
的缓冲区,因为 reinterpret_cast
的结果将始终引用新创建的对象(在 C++17 中 std::launder
仍然是必需的,但在 C++14 中这可以)。例如,
template<class T>
struct FakeOptional {
FakeOptional(){}
template<class... Args>
void emplace(Args&&... args){
new(&storage) T{std::forward<Args&&>(args)...};
}
void reset(){
reinterpret_cast<T*>(&storage)->~T();
}
operator bool() const {
return true;
}
const T* operator->() const {
return reinterpret_cast<const T*>(&storage);
}
T* operator->() {
return reinterpret_cast<T*>(&storage);
}
std::aligned_storage_t<sizeof(T), alignof(T)> storage;
};
执行 boost::optional
uses this idea and does not implement constexpr
semantic (you can refer to its source code 了解详情)。