std::map::size_type 用于其 value_type 是它自己的 size_type 的 std::map
Posted
技术标签:
【中文标题】std::map::size_type 用于其 value_type 是它自己的 size_type 的 std::map【英文标题】:std::map::size_type for a std::map whose value_type is its own size_type 【发布时间】:2019-04-25 03:45:41 【问题描述】:我有一个std::map<std::pair<std::string, std::string>, float>
,它占用了太多内存,为了使用更少的内存,我决定将唯一字符串映射到整数(例如,std::map<std::string, int>
,其中每个新的唯一字符串都被映射映射到当前的size()
),并将这些整数值用作映射的成对键(例如,std::map<std::pair<int, int>, float>
)。
我想用std::map::size_type代替int
:
using map_index = std::map::size_type;
std::pair<map_index, map_index> key;
当然,这不会编译,因为我需要为地图提供参数列表:
vector.cc:14:19: error: invalid use of template-name `std::map' without an argument list
using map_index = std::map::size_type;
这(理论上)是我想要实现的目标:
using map_index = std::map<std::string, map_index>::size_type;
它给出了以下(预期的)编译器错误:
vector.cc:15:41: error: `map_index' was not declared in this scope
using map_index = std::map<std::string, map_index>::size_type;
让编译器为 std::map
推断正确的 value_type
的正确方法是什么,而 value_type
是它自己的 size_type
?
【问题讨论】:
次要吹毛求疵:我认为你的最后一句话是错误的。要知道size_type
是什么,您首先需要知道value_type
是什么,而不是相反。一旦你知道地图的类型,得到它的size_type
就很简单了
@user463035818 问题似乎是size_type
是OP 的value_type
的一部分。
你有一个循环依赖。为什么你不能使用size_t
(这通常是size_type
)?
你能解释一下你为什么想要那个吗? afaik map::size_type
只是一个 typedef
别名无论如何总是相同的类型
std::map<K, V>::size_type
最有可能完全独立于K
和V
。如果你真的在意,可以static_assert(std::is_same_v<Map::size_type, Map::mapped_type>, "Unexpected size_type")
【参考方案1】:
size_t
应该足以应付这种情况。
但如果你坚持,你可以这样做:
#include <type_traits>
#include <map>
template <class Key, class Value = size_t, size_t depth = 0, class = void>
struct GetSizeType
using type = typename GetSizeType<Key, typename std::map<Key, Value>::size_type, depth + 1>::type;
;
template <class Key, class Value, size_t depth>
struct GetSizeType<Key, Value, depth, std::enable_if_t<std::is_same_v<Value, typename std::map<Key, Value>::size_type>>>
using type = typename std::map<Key, Value>::size_type;
;
template <class Key, class Value>
struct GetSizeType<Key, Value, 100, void> ;
int main()
using X = GetSizeType<int>::type;
return 0;
它将在GetSizeType
上递归运行,递归调用将停止
type
),或者
找到std::map
的特化,其中mapped_type
和size_type
相同(成员type
别名size_type
)。
【讨论】:
一阶的技术暴徒方法 - 太棒了! 我不完全同意“你会在用完 size_t 之前用完内存。”。像my_map.size() * 2;
这样的操作是一个明智的操作,它可以在内存不足之前很久就溢出
@user463035818 谢谢,我已经删除了那部分。我错误地简化了用法。
@user463035818 - 在问题设置的上下文中,不涉及算术 - size()
的结果只是被用作不透明的标识符。
@vallismortis “更极端的情况”是什么意思?如果你使用std::size_t
,它不可能在其他类型的地方不起作用,因为它应该能够处理大小为 1 的对象。【参考方案2】:
免责声明:这个解决方案非常愚蠢。我们将通过重复(通常一次)尝试实例化 std::map
来解决等式,直到我们找到一个具有请求的键和它自己的 size_type
作为值的那个。
template <class T>
struct identity
using type = T;
;
template <class K, class V = char>
struct auto_map
using map_type = std::map<K, V>;
using type = typename std::conditional_t<
std::is_same_v<
typename map_type::mapped_type,
typename map_type::size_type
>,
identity<map_type>,
auto_map<K, typename map_type::size_type>
>::type;
;
template <class K>
using auto_map_t = typename auto_map<K>::type;
如果元函数找不到这样的映射,它要么会因为type
最终定义给自己而出错,要么会打破递归限制。
【讨论】:
显示的两种递归解决方案都很酷,但我不确定为什么要使用它。正如您所说,它仍然不能保证您会找到在损坏的环境中工作的一个,因此编译以简单地选择一个并断言我们实际需要的条件会更干净,更快捷,不是吗? @Acorn 是的。在进行全面重建时,我只是需要做一些事情;)【参考方案3】:使用std::size_t
。无符号整数 std::map::size_type
不会大于 std::size_t
并且在实践中将是相同的类型。
如果你想确定,就断言它:
static_assert(std::is_same_v<
std::size_t,
std::map<std::string, std::size_t>::size_type
>);
【讨论】:
【参考方案4】:我使用的所有 C++ 实现对所有地图都使用相同的大小类型。
所以;
using map_size_type = std::map<int, int>::size_type;
using my_map = std::map<std::string, map_size_type>;
static_assert(std::is_same<map_size_type, my_map::size_type);
如果(合理的)假设失败,这只会强制编译错误。
【讨论】:
我在这里链接another question,因为您的回答似乎也与之相关。【参考方案5】:一般来说,您要寻找的东西是不可能的。
可以想象(尽管有些牵强)std::map<int, long>::size_type
是 int
和 std::map<int, int>::size_type
是 long
(对于其他整数类型也是如此),在这种情况下,没有可能的方法来满足 std::map<int, T>::size_type
是T
.
相反,对于所有T
,std::map<int, T>::size_type
可能被定义为T
,在这种情况下,没有唯一的T
满足您的“要求”。
正如几个答案(以及您自己的参考链接)所提到的,实际上它不太可能是 size_t
。
【讨论】:
这是我一直在寻找的答案,只是不是我所希望的。您提供的具体示例完美地说明了问题。【参考方案6】:打破循环依赖的唯一方法是使用特定类型。我建议您简单地将map_index
设为std::size_t
- C++ 强implies,std::size_t
将可分配给map::size_type
。
【讨论】:
【参考方案7】:但是您确定std::map
的size_type
取决于键/值类型吗?
如果是这样,我没有办法得到它。
但size_type
不应该依赖于键/值类型,通常是std::size_t
。
我建议
using Index0 = typename std::map<std::string, std::size_t>::size_type;
using mapIndex = typename std::map<std::string, Index0>::size_type;
你可以检查你是否得到了正确的类型
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
【讨论】:
编译器无法知道地图的大小类型始终相同 - 就它而言,可能存在不同的专业化。 @TobySpeight 是的,这正是促使我提出这个问题的原因。正是 C++ map documentation 中的“通常与 size_t 相同”子句真正让我想到了这一点。 @vallismortis - 从理论的角度来看,你是对的(据我所知)。我没有看到打破循环依赖的方法,但添加static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
您可以检查所选类型是否正确。
@TobySpeight - 你是对的(据我所知);但是通过static_assert()
(见我修改后的答案)我们可以检查我们是否得到了正确的类型。以上是关于std::map::size_type 用于其 value_type 是它自己的 size_type 的 std::map的主要内容,如果未能解决你的问题,请参考以下文章
Vue简明实用教程(03)——v-text和v-html指令
Vue简明实用教程(03)——v-text和v-html指令