标准说下面关于专门化模板从标准库(通过什么可以和不能我专门化std命名空间?)
只有当声明依赖于用户定义的类型并且专门化满足原始模板的标准库要求并且没有被明确禁止时,程序才可以将任何标准库模板的模板专门化添加到命名空间std。
使用专门用于用户定义类的标准库类来专门化标准库模板是否合法?
例如,将 std::hash
专用为 std::shared_ptr
从阅读上面的段落和链接的问题来看,听起来应该是这样,因为专业化的声明依赖于
MyType
,但是“除非明确禁止”让我有点担心。
下面的示例按预期编译和工作(AppleClang 7.3),但它合法吗?
#include <unordered_set>
#include <memory>
#include <cassert>
#include <string>
struct MyType {
MyType(std::string id) : id(id) {}
std::string id;
};
namespace std {
template<>
struct hash<shared_ptr<MyType>> {
size_t operator()(shared_ptr<MyType> const& mine) const {
return hash<string>()(mine->id);
}
};
template<>
struct equal_to<shared_ptr<MyType>> {
bool operator()(shared_ptr<MyType> const& lhs, shared_ptr<MyType> const& rhs ) const {
return lhs->id == rhs->id;
}
};
}
int main() {
std::unordered_set<std::shared_ptr<MyType>> mySet;
auto resultA = mySet.emplace(std::make_shared<MyType>("A"));
auto resultB = mySet.emplace(std::make_shared<MyType>("B"));
auto resultA2 = mySet.emplace(std::make_shared<MyType>("A"));
assert(resultA.second);
assert(resultB.second);
assert(!resultA2.second);
}
共1个答案
匿名用户
是的,这是合法的。
甚至专门化< code>std::shared_ptr也是不合法的
请注意,这是全局使用的散列的糟糕实现。首先,因为它不支持空共享指针。其次,因为像往常一样散列共享指针的int值是有问题的。这甚至是危险的,因为如果容器中指向int的共享指针发生了int更改,你就破坏了程序。
考虑为这类情况制作自己的哈希器。
namespace notstd {
template<class T, class=void>
struct hasher_impl:std::hash<T>{};
namespace adl_helper {
template<class T>
std::size_t hash( T const& t, ... ) {
return ::notstd::hasher_impl<T>{}(t);
}
};
namespace adl_helper2 {
template<class T>
std::size_t hash_helper(T const& t) {
using ::notstd::adl_helper::hash;
return hash(t);
}
}
template<class T>
std::size_t hash(T const& t) {
return ::notstd::adl_helper2::hash_helper(t);
}
struct hasher {
template<class T>
std::size_t operator()(T const& t)const {
return hash(t);
}
};
}
现在,这允许3点定制。
首先,如果您覆盖了< code>std::size_t hash(T const
如果做不到这一点,如果你专注于notstd::hasher_impl
第三,如果这两个都失败,它调用< code>std::hash
然后您可以执行以下操作:
std::unordered_set<std::shared_ptr<MyType>, ::notstd::hasher> mySet;
并补充:
struct MyType {
MyType(std::string id) : id(id) {}
std::string id;
friend std::size_t hash( MyType const& self) {
return ::notstd::hash(self.id);
}
friend std::size_t hash( std::shared_ptr<MyType> const& self) {
if (!self) return 0;
return ::notstd::hash(*self);
}
};
这应该会给你一个关于的智能哈希shared_ptr
这就避免了有人在shared_ptr上更改id
的危险
共享状态是魔鬼;如果你真的担心复制这些东西会很昂贵,那么考虑在写指针上写一个副本。
相关问题
- 在笑话中,定义全局变量是否与在BeforeAll中定义相同?
- 异步管道是否从服务中定义并从组件变量指向的可观察对象取消订阅?
- “this”在ngOnDestroy中未定义
- 订阅的自定义完成方法是否会自行取消订阅?
- 如果没有“订阅”类型的对象,如何取消订阅可观察?
- 获取API获取415不支持的媒体类型使用POST
- 返回415不支持的媒体类型REST客户端的响应状态
- 对于所有对象类型T,sizeof(T)>=对(T)总是这样吗?
- std::向量在哪里分配内存?
- C 20概念需要运算符重载结合用户自定义模板运算符重载功能
- Visual C关系运算符重载const正确性(使用std::排序)
- 是否对参与部分排序的类型进行实例化
- 部分排序时,成员函数模板的原始类型是什么
- 如何检测用户是否加入语音频道的任何人?
- 如何检测到用户在语音聊天中被静音,并使用dis和py自动取消静音?
- Jlink-包括JavaFX应用程序中包含自定义python脚本的目录
- 并发HashMap与基于ReentantReadWriteLock的自定义重新加载映射
- 为什么具有顺序一致性的std::atomic存储使用XCHG?
- JavaFX:自定义ListView单元格的内容样式
- 在Spring Boot中使用Java配置在bean定义之外别名bean