如何使用自定义比较器为三元组(“tuple”)声明/使用“unordered_set”?

2023-12-19

如何声明/使用unordered_set对于三胞胎(tuple)使用自定义比较器?

我需要存储三元组float(处理为tuple)在一组中检查潜在的重复项。因为它是关于float,我想使用常规比较==不起作用,因此需要自定义比较。

这个最小的代码无法编译:

>> cat unordered_set_triplet.cpp 
#include <unordered_set>
#include <tuple>
#include <limits> // numeric_limits
#include <cmath> // fabs
#include <functional> // hash

using triplet = std::tuple<float, float, float>;
bool triplet_equal(triplet const & lhs, triplet const & rhs) {
  float const eps = std::numeric_limits<float>::epsilon();
  if (std::fabs(std::get<0>(lhs) - std::get<0>(rhs)) > eps) return false;
  if (std::fabs(std::get<1>(lhs) - std::get<1>(rhs)) > eps) return false;
  if (std::fabs(std::get<2>(lhs) - std::get<2>(rhs)) > eps) return false;
  return true;
}
using unordered_set_triplet = std::unordered_set<triplet,
                                                 std::hash<triplet>,
                                                 decltype(triplet_equal)>;

int main() {
  //unordered_set_triplet s; // Compilation: KO...
  unordered_set_triplet s(10, std::hash<triplet>, triplet_equal);
  s.insert({1.f, 2.f, 3.f});
}

I get:

>> g++ -std=c++20 -o unordered_set_triplet unordered_set_triplet.cpp 
In file included from /usr/include/c++/12/bits/hashtable.h:35,
                 from /usr/include/c++/12/unordered_set:46,
                 from unordered_set_triplet.cpp:1:
/usr/include/c++/12/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::_Hashtable_ebo_helper<0, bool(const std::tuple<float, float, float>&, const std::tuple<float, float, float>&), false>’:
/usr/include/c++/12/bits/hashtable_policy.h:1631:12:   required from ‘struct std::__detail::_Hashtable_base<std::tuple<float, float, float>, std::tuple<float, float, float>, std::__detail::_Identity, bool(const std::tuple<float, float, float>&, const std::tuple<float, float, float>&), std::hash<std::tuple<float, float, float> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Hashtable_traits<true, true, true> >’
/usr/include/c++/12/bits/hashtable.h:182:11:   required from ‘class std::_Hashtable<std::tuple<float, float, float>, std::tuple<float, float, float>, std::allocator<std::tuple<float, float, float> >, std::__detail::_Identity, bool(const std::tuple<float, float, float>&, const std::tuple<float, float, float>&), std::hash<std::tuple<float, float, float> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, true, true> >’
/usr/include/c++/12/bits/unordered_set.h:100:18:   required from ‘class std::unordered_set<std::tuple<float, float, float>, std::hash<std::tuple<float, float, float> >, bool(const std::tuple<float, float, float>&, const std::tuple<float, float, float>&)>’
unordered_set_triplet.cpp:21:26:   required from here
/usr/include/c++/12/bits/hashtable_policy.h:1204:11: error: data member ‘std::__detail::_Hashtable_ebo_helper<0, bool(const std::tuple<float, float, float>&, const std::tuple<float, float, float>&), false>::_M_tp’ invalidly declared function type
 1204 |       _Tp _M_tp{};
      |           ^~~~~
/usr/include/c++/12/bits/hashtable.h: In instantiation of ‘class std::_Hashtable<std::tuple<float, float, float>, std::tuple<float, float, float>, std::allocator<std::tuple<float, float, float> >, std::__detail::_Identity, bool(const std::tuple<float, float, float>&, const std::tuple<float, float, float>&), std::hash<std::tuple<float, float, float> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, true, true> >’:
/usr/include/c++/12/bits/unordered_set.h:100:18:   required from ‘class std::unordered_set<std::tuple<float, float, float>, std::hash<std::tuple<float, float, float> >, bool(const std::tuple<float, float, float>&, const std::tuple<float, float, float>&)>’
unordered_set_triplet.cpp:21:26:   required from here
/usr/include/c++/12/bits/hashtable.h:665:7: error: function returning a function
  665 |       key_eq() const
      |       ^~~~~~
In file included from /usr/include/c++/12/unordered_set:47:
/usr/include/c++/12/bits/unordered_set.h: In instantiation of ‘class std::unordered_set<std::tuple<float, float, float>, std::hash<std::tuple<float, float, float> >, bool(const std::tuple<float, float, float>&, const std::tuple<float, float, float>&)>’:
unordered_set_triplet.cpp:21:26:   required from here
/usr/include/c++/12/bits/unordered_set.h:632:7: error: function returning a function
  632 |       key_eq() const
      |       ^~~~~~
unordered_set_triplet.cpp: In function ‘int main()’:
unordered_set_triplet.cpp:21:49: error: expected primary-expression before ‘,’ token
   21 |   unordered_set_triplet s(10, std::hash<triplet>, triplet_equal);
      |                                                 ^

如何解决这个问题?

EDIT

使用(已订购)也不起作用set:

>> cat set_triplet.cpp 
#include <iostream>
#include <set>
#include <tuple>
#include <limits> // numeric_limits
#include <cmath> // fabs
#include <functional> // hash

using triplet = std::tuple<float, float, float>;
bool triplet_equal(triplet const & lhs, triplet const & rhs) {
  float const eps = std::numeric_limits<float>::epsilon();
  if (std::fabs(std::get<0>(lhs) - std::get<0>(rhs)) > eps) return false;
  if (std::fabs(std::get<1>(lhs) - std::get<1>(rhs)) > eps) return false;
  if (std::fabs(std::get<2>(lhs) - std::get<2>(rhs)) > eps) return false;
  return true;
}
using set_triplet = std::set<triplet, std::hash<triplet>, decltype(triplet_equal)>;

int main() {
  //set_triplet s; // Compilation: KO...
  set_triplet s(10, std::hash<triplet>, triplet_equal);
  s.insert({1.f, 2.f, 3.f});
  s.insert({1.0000001f, 2.0000001f, 3.0000001f});
  for (auto const & t : s) std::cout << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << std::endl;
}

什么容器适合使用?triplet可以看到 3D 点 (XYZ):我需要处理/检测重复点。

解决方案:使用 SET(非无序集)和 INT(非浮点型)而不实现 Less

使用由整数组成的元组i这样建的i = (int) 1000000 * f来自浮动f并使用集合(如operator<乘以 1000000 后将遵守高达 6 位精度的严格排序)。

>> cat set_uint32_triplet.cpp 
#include <iostream>
#include <set>
#include <tuple>

using triplet_uint32 = std::tuple<uint32_t, uint32_t, uint32_t>;
using triplet_float = std::tuple<float, float, float>;
triplet_uint32 convert(triplet_float const & f) {
  uint32_t precision = 1000000; // Allow for 6-digit precision.
  uint32_t x = (uint32_t) (std::get<0>(f) * precision);
  uint32_t y = (uint32_t) (std::get<1>(f) * precision);
  uint32_t z = (uint32_t) (std::get<2>(f) * precision);
  return {x, y, z};
}

int main() {
  triplet_float pt1 = {1.f, 2.f, 3.f};
  triplet_float pt2 = {1.0000001f, 2.0000001f, 3.0000001f}; // Considered     duplicate with pt1.
  triplet_float pt3 = {1.000001f,  2.000001f,  3.000001f};  // Considered NOT duplicate with pt1.

  std::set<triplet_uint32> s;
  s.insert(convert(pt1));
  s.insert(convert(pt2));
  s.insert(convert(pt3));
  std::cout << "set size " << s.size() << std::endl;
  for (auto const & t : s) std::cout << "set item " << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << ", " << std::endl;
}

>> g++ -std=c++20 -o set_uint32_triplet set_uint32_triplet.cpp

>> ./set_uint32_triplet 
set size 2
set item 1000000, 2000000, 3000000, 
set item 1000000, 2000001, 3000001, 

解决方案:使用 SET(非无序集)和 INT(非浮点型)并实现 Less

>> cat set_uint32_triplet_less.cpp 
#include <iostream>
#include <set>
#include <tuple>

#define FLOAT_TO_INT(x) ((x)>=0?(int32_t)((x)+0.5):(int32_t)((x)-0.5))

using triplet_int32 = std::tuple<int32_t, int32_t, int32_t>;
using triplet_float = std::tuple<float, float, float>;
triplet_int32 convert(triplet_float const & f) {
  int32_t precision = 1000; // Allow for 3-digit precision.
  int32_t x = FLOAT_TO_INT(std::get<0>(f) * precision);
  int32_t y = FLOAT_TO_INT(std::get<1>(f) * precision);
  int32_t z = FLOAT_TO_INT(std::get<2>(f) * precision);
  //std::cout.precision(10);
  //std::cout << "convert: " << std::get<0>(f) << ", " << std::get<1>(f) << ", " << std::get<2>(f);
  //std::cout << " - " << std::get<0>(f) * precision << ", " << std::get<1>(f) * precision << ", " << std::get<2>(f) * precision;
  //std::cout << " - " << FLOAT_TO_INT(std::get<0>(f) * precision) << ", " << FLOAT_TO_INT(std::get<1>(f) * precision) << ", " << FLOAT_TO_INT(std::get<2>(f) * precision);
  //std::cout << " - " << x << ", " << y << ", " << z << std::endl;
  return {x, y, z};
}
struct less {
  bool operator()(triplet_int32 const & lhs,
                  triplet_int32 const & rhs) const {
    bool res = true; // lhs < rhs.
    if      (std::get<0>(lhs) >= std::get<0>(rhs)) res = false;
    else if (std::get<1>(lhs) >= std::get<1>(rhs)) res = false;
    else if (std::get<2>(lhs) >= std::get<2>(rhs)) res = false;
    //std::cout << "  less: " << std::get<0>(lhs) << ", " << std::get<1>(lhs) << ", " << std::get<2>(lhs);
    //std::cout <<    " - " << std::get<0>(rhs) << ", " << std::get<1>(rhs) << ", " << std::get<2>(rhs);
    //std::cout << " - res " << res << std::endl;
    return res; // lhs < rhs.
  }
};

int main() {
  triplet_float pt1 = {1.f, 2.f, 3.f};
  triplet_float pt2 = {1.0001f, 2.0001f, 3.0001f}; // Considered     duplicate with pt1.
  triplet_float pt3 = {1.001f,  2.001f,  3.001f};  // Considered NOT duplicate with pt1.

  std::set<triplet_int32, less> s;
  s.insert(convert(pt1));
  s.insert(convert(pt2));
  s.insert(convert(pt3));
  std::cout << "set size " << s.size() << std::endl;
  for (auto const & t : s) std::cout << "set item " << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << ", " << std::endl;
}
>> g++ -std=c++20 -o set_uint32_triplet_less set_uint32_triplet_less.cpp
>> ./set_uint32_triplet_less 
set size 2
set item 1000, 2000, 3000, 
set item 1001, 2001, 3001, 

这可能不是您想要的答案,但它为您提供了已接受答案的传递性问题的解决方案。

Use std::tuple<int, int, int>并通过将浮点数乘以某个常数(例如 10000)并向下舍入来量化浮点数。比例因子将取决于您的域。

如果需要保留原始值,请使用 unordered_map。使用 int 元组作为键,并添加一个 float 元组作为值。 然后,当您搜索给定的三元组时,您可以在三个值中的每个值中查找相邻元组。

这更复杂,工作量更大,但这是一种更正确的方法,并且可以避免由于传递性问题而导致的 UB。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用自定义比较器为三元组(“tuple”)声明/使用“unordered_set”? 的相关文章

随机推荐

  • Unity 3d Sprite Shader(如何在多个灯光照射下将最大亮度限制为 1)

    我正在 Unity 中创建一个视频游戏 每个精灵都使用具有 CornucopiaShader shader 材质的精灵渲染器进行渲染 我遇到的问题是我想将精灵的最大亮度 或颜色 限制为精灵的正常图像 无论有多少点光源照射它的功率 灯光的强度
  • 为什么shared_ptr<>必须分别分配控制块和托管对象?

    这个链接的问题询问是否make shared lt gt 函数和shared ptr lt gt 构造函数不同 使用 make shared 时会发生什么 https stackoverflow com questions 24779929
  • Spring批处理聚合值并写入单个值

    我正在使用 spring Batch 我需要实现以下目标 读取包含日期和金额等详细信息的 csv 文件 汇总同一日期所有金额的总和 保留一项包含日期和总和的条目 我过去使用过批处理 我想到了以下方法 创建一个批次需要 2 个步骤 Step
  • devise Rails current_user 与 user_signed_in?

    我正在使用 Devise on Rails 4 1 我的问题是关于助手以及它们与会话的关系 current user 告诉您是否有可供该用户使用的用户会话 user signed in 告诉您用户是否已通过身份验证 我无法理解如果 user
  • WebClient.DownloadingString 更改请求的 URL

    如果我在浏览器中输入 URL 我的服务器会正 确响应 XML 虽然 如果这个相同的 URL 通过 WebClient DownloadingString 方法 URL 中的某些内容会发生变化 并且我的服务器会正 确响应 但会显示访问被拒绝消
  • 使用 basichttpbinding 调用 wcf webservice,无需 REST 或 JSON

    我有一个通过 wsHTTPBinding 和 basicHTTPBinding 公开的 wcf Web 服务 后者将其端点地址指定为 basic 如下所示
  • 使用 Web api 和 asp.net mvc 5 进行单点登录

    我希望将 SSO 与 Web api 2 2 结合使用 以便在多个应用程序中使用 包括移动和 asp net mvc 5 我了解了通过 Web api 创建身份验证令牌的基本想法 但我有几个问题 1 将身份验证令牌与用户名一起存储在 coo
  • 如何使用 LINQ Contains() 查找枚举列表?

    我有一个名为OrderStatus 它包含订单可以处于的各种状态 Created Pending Waiting Valid Active 处理 完全的 我想要做的是创建一个 LINQ 语句 该语句将告诉我 OrderStaus 是否有效
  • php7.4 mysqli 因“消失”而超时

    我刚刚安装了 php7 4 一切似乎都正常 但是当我尝试继续我的 phpmyadmin 时 我不能 注意在此安装之前在 php7 3 中工作正常 错误是 mysqli real connect Unexpected server respo
  • 将 Ruby 中的持续时间 - hh:mm:ss.sss 转换为毫秒,反之亦然

    我想知道 Ruby 中是否有一个内置方法可以让我将 hh mm ss sss 格式的单圈时间转换为毫秒 反之亦然 由于我需要用它进行一些计算 因此我认为转换为毫秒将是最简单的方法 告诉我我是否错了 这个怎么样 a 1 1000 60000
  • hibernate中的@Fetch注解是什么?

    OneToMany cascade CascadeType ALL fetch FetchType EAGER orphanRemoval true Fetch FetchMode SUBSELECT JoinColumn name ORU
  • 批次中%~1和%1有什么区别?

    在批次中我有时会看到 1用于开关 也用于 1 有什么不同 他们似乎都为我工作 Example if 1 echo No variable specified and if 1 echo No variable specified 似乎可以互
  • 为什么我的 Bash 脚本将 添加到文件开头?

    我编写了一个脚本 使用 sed 清理 csv 文件 删除一些错误的逗号和错误的引号 不好的 意味着它们破坏了我们用来转换这些文件的内部程序 remove all commas and re insert the good commas us
  • 使用 Azure 管理 API 进行身份验证

    我们使用 Azure API 进行各种操作已经有一段时间了 例如 这是我们使用的 API 之一https learn microsoft com en us rest api servicebus namespaces createorup
  • Bootstrap 4 垂直对齐文本不会在卡片上居中

    尝试垂直对齐以下卡片中的文本中心 div class row text center h 100 div class col md 3 text center my auto div class card card block justif
  • 如何提取嵌套的 JSON 数据?

    我正在尝试从 JSON 数据中获取值 我已经成功地深入到了 JSON 数据 几乎得到了我需要的东西 在 Python 中运行此命令 autoscaling name response Reservations 0 Instances 0 T
  • skel.js 框架/HTML5UP 模板 CSS 问题

    我是 skel js 框架的新手 遇到了一些问题 我从 HTML5UP net Zerofour 主题 下载了一个模板 并且已经为我的网站修改了所有内容 但是 CSS 没有在我的网站上正确显示无侧边栏 左侧边栏 pages 我包含以下链接
  • 用于提取部分文件路径的正则表达式

    我在 Impala 中使用正则表达式函数来查找文件路径中的文件夹名称 但它似乎没有给我正确的结果 我想从这个文件路径中解析出 一 this one path to hdfs 这是我使用的正则表达式 regexp extract filepa
  • 如何在 Angular 2 Webpack 中使用 WOW.js?

    我知道我们需要 wow js 的打字文件 但我在任何地方都找不到它 有没有其他解决方案可以将此外部js加载到webpack中 执行以下步骤 安装出口装载机 https www npmjs com package exports loader
  • 如何使用自定义比较器为三元组(“tuple”)声明/使用“unordered_set”?

    如何声明 使用unordered set对于三胞胎 tuple 使用自定义比较器 我需要存储三元组float 处理为tuple 在一组中检查潜在的重复项 因为它是关于float 我想使用常规比较 不起作用 因此需要自定义比较 这个最小的代码