C++类类型双关语
C++ type punning with classes
我正在编写一些包装 std::unordered_map 类型的C++代码,我想在其中隐藏底层类型并将其呈现为另一种类型。更具体地说,我想用另一种类型包装 std::p air 从 std::unordered_map。为了便于讨论,让我们假设包装器看起来像这样...
template <typename ActualT >
class wrapper final
{
private:
ActualT actual_;
public:
//Some constructors...
typename ActualT::first_type & get_first()
{
return actual_.first;
}
typename ActualT::second_type & get_second()
{
return actual_.second;
}
};
我的推理是,由于包装类只有一个成员,该成员是它所包装的确切类型,因此将引用从原始类型转换为包装器类型应该没问题,但是结构的类型兼容性指出成员应该具有相同的类型和名称才能兼容的类型。以这种方式使用类型双关是否可能会导致未定义的行为或对齐问题?
using my_map = std::unordered_map < int, int >;
my_map m;
//Do some inserts...
reinterpret_cast<wrapper<typename my_map::value_type>&>(*m.find(10)).get_second() = 1.0;
我希望允许客户端代码访问映射的条目,而无需知道映射返回的对。我还想编写一个自定义转发迭代器,因此我需要返回对该条目的引用。将对货币对的引用转换为对充当包装器的类的引用是否被认为是危险的?
有没有更好的方法来实现这一目标?
这绝对是未定义的行为。
认真重新考虑您的优先事项。
表单的一些免费函数
const my_map::key_type & MeaningfulNameHere(my_map::reference)
将大大有助于为您提供有意义的名称。
如果必须使用不同的名称包装标准库,只需使用非显式构造函数并存储引用。
template <typename Map>
class entry final
{
private:
typename Map::reference ref;
public:
entry(Map::reference ref) : ref(ref) {}
const typename Map::key_type & key()
{
return ref.first;
}
typename Map::mapped_type & value()
{
return ref.second;
}
};
如果您确实需要迭代器取消引用entry
则可以。但是你可以从Map::iterator::operator*
返回的Map::reference
中隐式实例化entry
s,你不需要自定义迭代器。
template <typename Map>
class entry_iterator
{
private:
typename Map::iterator it;
entry<Map> entry;
public:
entry<Map>& operator*() { return entry; }
entry_iterator operator++() { ++it; entry = *it; return *this; }
// etc
}
所以你可以清理一下,但我不建议这样做:
#include <unordered_map>
#include <iostream>
using namespace std;
template <class Key, class Value>
class wrapper
{
public:
explicit wrapper(std::pair<const Key, Value>& kvp)
: _key{kvp.first}
, _value{kvp.second}
{}
const Key& key() const { return _key; }
Value& value() { return _value; }
private:
const Key& _key;
Value& _value;
};
int main()
{
unordered_map<int,int> m;
m[1] = 1;
m[3] = 3;
auto it = m.find(1);
wrapper w{*it};
w.value() = 30;
std::cout << w.key() << " -> " << w.value() << 'n';
}
上述内容有效地对类的用户隐藏了pair
。 它不处理异常(例如find()
返回end()
(,并且不保证生命周期。 它比你拥有的略好,因为它不需要reinterpret_cast
到不相关的类型。
然而,map
、unordered_map
、set
等将返回迭代器存储为对只是库的一部分——它是规范形式,我没有看到保护人们免受它的好处。
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 如何判断类型双关语在我的平台上是否可以?
- 为什么这种类型的双关语不是未定义的行为?
- C++类类型双关语
- C++通过回退到 C 进行类型双关语
- 为什么 std::memcpy(作为类型双关语的替代方案)不会导致未定义的行为?
- 什么是类型双关语,它的目的是什么?
- 这种类型的双关语是否合法和安全
- 这种类型的双关语是否定义良好
- 无符号整数的类型双关语是否可以通过消除 >= 比较的需要来加快边界检查速度?
- 使用模板进行类型双关语强制转换
- c++中安全有效的类型双关语