相对问题,但是我想要一个没有任何运行时开销的解决方案。(因此,构建一个新的pair或使用std::variant并不是答案)
由于潜在的模板专业化,参考文献说pair<K, V>和pair<const K, V>并不相似,这意味着简单的reinterpret_cast会触发未定义的行为。
auto p1 = pair<int, double>{ 1, 2.3 };
auto& p2 = reinterpret_cast<pair<const int, double>&>(p1); // UB!通过union进行类型双关在C中工作得很好,但在C++中并不总是合法的:
但是有一个例外(与C中的行为一致):
由于Key和Value可能不是standard-layout,并且可能有non-trivial析构函数,所以这里似乎不可能进行类型双关,尽管pair<Key, Value>和pair<const Key, Value>的成员可以共享相同的生存期(当然是使用对齐断言)。
template <typename Key, typename Value>
union MapPair {
using TrueType = pair<Key, Value>;
using AccessType = pair<const Key, Value>;
static_assert(
offsetof(TrueType, first) == offsetof(AccessType, first)
&& offsetof(TrueType, second) == offsetof(AccessType, second)
&& sizeof(TrueType) == sizeof(AccessType)
);
TrueType truePair;
AccessType accessPair;
~MapPair() {
truePair.~pair();
}
// constructors for `truePair`
};
//...
auto mapPair = MapPair<NonTrivialKey, NonTrivialValue>{/*...*/};
// UB? Due to the lifetime of `truepair` is not terminated?
auto& accessPair = reinterpret_cast<pair<const NonTrivialKey, NonTrivialValue>&>(mapPair);
// still UB? Although objects on the buffer share the same constructor/destructor and lifetime
auto* accessPairPtr = std::launder(reinterpret_cast<pair<const NonTrivialKey, NonTrivialValue>*>(&mapPair));我注意到了std::map::extract和Node handle的保证。因此,我相信一些类似的行为(类型双关语或const_cast)确实存在于与Node handle相关的STL实现中。
在libc++中,它似乎依赖于clang (不为数据成员优化)的特性,而不是标准。
libstdc++执行libc++,但没有刷新类型状态的std::launder。
MSVC .非常令人惊讶..。而且提交历史太短,我找不到支持如此简单的混叠的任何理由。
这里有标准的方法吗?
发布于 2022-06-25 15:15:22
这是不可能的。node_handle的提案提到这是标准化的一个动机:
标准库存在的原因之一是编写客户端无法用可移植C++ (例如,>等)编写的不可移植和神奇的代码。这只是另一个例子。请注意,
key成员函数是唯一需要此类技巧的地方,并且不需要对容器或对进行更改。
https://stackoverflow.com/questions/72670928
复制相似问题