std::map::size_type for a std::map whose value_type is its own size_type
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have a std::map<std::pair<std::string, std::string>, float>
that is taking up too much memory, and in order to use less memory, I've decided to map the unique strings to integers (e.g., std::map<std::string, int>
, where each new unique string is mapped to the current size()
of the map), and use those integer value as pairwise keys to the map, (e.g., std::map<std::pair<int, int>, float>
).
Instead of int
, I want to use std::map::size_type:
using map_index = std::map::size_type;
std::pair<map_index, map_index> key;
Of course, this doesn't compile because I need to supply the argument list for the map:
vector.cc:14:19: error: invalid use of template-name `std::map' without an argument list
using map_index = std::map::size_type;
And this (in theory) is what I'm trying to achieve:
using map_index = std::map<std::string, map_index>::size_type;
which gives the following (expected) compiler error:
vector.cc:15:41: error: `map_index' was not declared in this scope
using map_index = std::map<std::string, map_index>::size_type;
What is the proper way to get the compiler to infer the correct value_type
for a std::map
whose value_type
is its own size_type
?
c++ c++11 stl stdmap size-type
|
show 3 more comments
I have a std::map<std::pair<std::string, std::string>, float>
that is taking up too much memory, and in order to use less memory, I've decided to map the unique strings to integers (e.g., std::map<std::string, int>
, where each new unique string is mapped to the current size()
of the map), and use those integer value as pairwise keys to the map, (e.g., std::map<std::pair<int, int>, float>
).
Instead of int
, I want to use std::map::size_type:
using map_index = std::map::size_type;
std::pair<map_index, map_index> key;
Of course, this doesn't compile because I need to supply the argument list for the map:
vector.cc:14:19: error: invalid use of template-name `std::map' without an argument list
using map_index = std::map::size_type;
And this (in theory) is what I'm trying to achieve:
using map_index = std::map<std::string, map_index>::size_type;
which gives the following (expected) compiler error:
vector.cc:15:41: error: `map_index' was not declared in this scope
using map_index = std::map<std::string, map_index>::size_type;
What is the proper way to get the compiler to infer the correct value_type
for a std::map
whose value_type
is its own size_type
?
c++ c++11 stl stdmap size-type
minor nitpick: I think you have the last sentence the wrong way around. To know what issize_type
you first need to tell what is thevalue_type
not the other way around. Once you know the type of the map, getting itssize_type
is trivial
– user463035818
Nov 22 '18 at 12:44
@user463035818 The problem seems to be that thesize_type
is a part ofvalue_type
for the OP.
– Some programmer dude
Nov 22 '18 at 12:46
5
You have a circular dependency. Why can't you usesize_t
(which is whatsize_type
normally will be anyway)?
– Some programmer dude
Nov 22 '18 at 12:47
can you explain why you want that? afaikmap::size_type
is just atypedef
aliasing always the same type anyhow
– user463035818
Nov 22 '18 at 12:47
3
std::map<K, V>::size_type
is most likely completely independent of bothK
andV
. If you really care, you canstatic_assert(std::is_same_v<Map::size_type, Map::mapped_type>, "Unexpected size_type")
– Caleth
Nov 22 '18 at 12:59
|
show 3 more comments
I have a std::map<std::pair<std::string, std::string>, float>
that is taking up too much memory, and in order to use less memory, I've decided to map the unique strings to integers (e.g., std::map<std::string, int>
, where each new unique string is mapped to the current size()
of the map), and use those integer value as pairwise keys to the map, (e.g., std::map<std::pair<int, int>, float>
).
Instead of int
, I want to use std::map::size_type:
using map_index = std::map::size_type;
std::pair<map_index, map_index> key;
Of course, this doesn't compile because I need to supply the argument list for the map:
vector.cc:14:19: error: invalid use of template-name `std::map' without an argument list
using map_index = std::map::size_type;
And this (in theory) is what I'm trying to achieve:
using map_index = std::map<std::string, map_index>::size_type;
which gives the following (expected) compiler error:
vector.cc:15:41: error: `map_index' was not declared in this scope
using map_index = std::map<std::string, map_index>::size_type;
What is the proper way to get the compiler to infer the correct value_type
for a std::map
whose value_type
is its own size_type
?
c++ c++11 stl stdmap size-type
I have a std::map<std::pair<std::string, std::string>, float>
that is taking up too much memory, and in order to use less memory, I've decided to map the unique strings to integers (e.g., std::map<std::string, int>
, where each new unique string is mapped to the current size()
of the map), and use those integer value as pairwise keys to the map, (e.g., std::map<std::pair<int, int>, float>
).
Instead of int
, I want to use std::map::size_type:
using map_index = std::map::size_type;
std::pair<map_index, map_index> key;
Of course, this doesn't compile because I need to supply the argument list for the map:
vector.cc:14:19: error: invalid use of template-name `std::map' without an argument list
using map_index = std::map::size_type;
And this (in theory) is what I'm trying to achieve:
using map_index = std::map<std::string, map_index>::size_type;
which gives the following (expected) compiler error:
vector.cc:15:41: error: `map_index' was not declared in this scope
using map_index = std::map<std::string, map_index>::size_type;
What is the proper way to get the compiler to infer the correct value_type
for a std::map
whose value_type
is its own size_type
?
c++ c++11 stl stdmap size-type
c++ c++11 stl stdmap size-type
edited Nov 22 '18 at 13:53
vallismortis
asked Nov 22 '18 at 12:41
vallismortisvallismortis
3,743104366
3,743104366
minor nitpick: I think you have the last sentence the wrong way around. To know what issize_type
you first need to tell what is thevalue_type
not the other way around. Once you know the type of the map, getting itssize_type
is trivial
– user463035818
Nov 22 '18 at 12:44
@user463035818 The problem seems to be that thesize_type
is a part ofvalue_type
for the OP.
– Some programmer dude
Nov 22 '18 at 12:46
5
You have a circular dependency. Why can't you usesize_t
(which is whatsize_type
normally will be anyway)?
– Some programmer dude
Nov 22 '18 at 12:47
can you explain why you want that? afaikmap::size_type
is just atypedef
aliasing always the same type anyhow
– user463035818
Nov 22 '18 at 12:47
3
std::map<K, V>::size_type
is most likely completely independent of bothK
andV
. If you really care, you canstatic_assert(std::is_same_v<Map::size_type, Map::mapped_type>, "Unexpected size_type")
– Caleth
Nov 22 '18 at 12:59
|
show 3 more comments
minor nitpick: I think you have the last sentence the wrong way around. To know what issize_type
you first need to tell what is thevalue_type
not the other way around. Once you know the type of the map, getting itssize_type
is trivial
– user463035818
Nov 22 '18 at 12:44
@user463035818 The problem seems to be that thesize_type
is a part ofvalue_type
for the OP.
– Some programmer dude
Nov 22 '18 at 12:46
5
You have a circular dependency. Why can't you usesize_t
(which is whatsize_type
normally will be anyway)?
– Some programmer dude
Nov 22 '18 at 12:47
can you explain why you want that? afaikmap::size_type
is just atypedef
aliasing always the same type anyhow
– user463035818
Nov 22 '18 at 12:47
3
std::map<K, V>::size_type
is most likely completely independent of bothK
andV
. If you really care, you canstatic_assert(std::is_same_v<Map::size_type, Map::mapped_type>, "Unexpected size_type")
– Caleth
Nov 22 '18 at 12:59
minor nitpick: I think you have the last sentence the wrong way around. To know what is
size_type
you first need to tell what is the value_type
not the other way around. Once you know the type of the map, getting its size_type
is trivial– user463035818
Nov 22 '18 at 12:44
minor nitpick: I think you have the last sentence the wrong way around. To know what is
size_type
you first need to tell what is the value_type
not the other way around. Once you know the type of the map, getting its size_type
is trivial– user463035818
Nov 22 '18 at 12:44
@user463035818 The problem seems to be that the
size_type
is a part of value_type
for the OP.– Some programmer dude
Nov 22 '18 at 12:46
@user463035818 The problem seems to be that the
size_type
is a part of value_type
for the OP.– Some programmer dude
Nov 22 '18 at 12:46
5
5
You have a circular dependency. Why can't you use
size_t
(which is what size_type
normally will be anyway)?– Some programmer dude
Nov 22 '18 at 12:47
You have a circular dependency. Why can't you use
size_t
(which is what size_type
normally will be anyway)?– Some programmer dude
Nov 22 '18 at 12:47
can you explain why you want that? afaik
map::size_type
is just a typedef
aliasing always the same type anyhow– user463035818
Nov 22 '18 at 12:47
can you explain why you want that? afaik
map::size_type
is just a typedef
aliasing always the same type anyhow– user463035818
Nov 22 '18 at 12:47
3
3
std::map<K, V>::size_type
is most likely completely independent of both K
and V
. If you really care, you can static_assert(std::is_same_v<Map::size_type, Map::mapped_type>, "Unexpected size_type")
– Caleth
Nov 22 '18 at 12:59
std::map<K, V>::size_type
is most likely completely independent of both K
and V
. If you really care, you can static_assert(std::is_same_v<Map::size_type, Map::mapped_type>, "Unexpected size_type")
– Caleth
Nov 22 '18 at 12:59
|
show 3 more comments
7 Answers
7
active
oldest
votes
What you are looking for is, generally speaking, impossible.
It's conceivable (though far-fetched) that std::map<int, long>::size_type
is int
and std::map<int, int>::size_type
is long
(and similarly for other integer types), in which case there is no possible way to satisfy std::map<int, T>::size_type
being T
.
Conversely, it could be that std::map<int, T>::size_type
is defined as T
for all T
, in which case there is no unique T
satisfying your "requirement".
As mentioned by several answers (and your own reference link), in practice it's unlikely to be anything else than size_t
.
This is the answer I was looking for, it just isn't the one I was hoping for. The specific examples you provide illustrate the problem perfectly.
– vallismortis
Nov 22 '18 at 13:27
add a comment |
size_t
should be good enough for such case.
But if you insist, you can do like this:
#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;
}
It will run recursively on GetSizeType
, the recursive call will stop upon
- reaching the recursive call depth limitation (there will be no member
type
in this case), or - finding a specialization of
std::map
of which themapped_type
andsize_type
is identical (the membertype
aliasessize_type
).
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 '18 at 13:02
1
i dont completely agree with " You will run out of memory before running out of size_t.". Something likemy_map.size() * 2;
is a sensible operation that can overflow long before you run out of memory
– user463035818
Nov 22 '18 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 '18 at 13:07
1
@user463035818 - in the context set by the question, there's no arithmetic involved - the result ofsize()
is simply being used as an opaque identifier.
– Toby Speight
Nov 22 '18 at 13:08
1
@vallismortis What do you mean by "more extreme cases"? If you usestd::size_t
, there is no way it won't work where another type would, because that should be able to address even objects of size 1.
– Acorn
Nov 22 '18 at 13:22
|
show 5 more comments
Disclaimer: this solution is pretty dumb. We're just going to solve the equation by repeatedly (typically once) trying to instantiate std::map
until we find one that has the requested key and its own size_type
as value.
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;
If the metafunction can't find such a map, it will either error out because type
ends up defined to itself, or break the recursion limit.
Both recursive solutions shown are cool, but I am unsure why one would use this. It still does not guarantee you will find one that works in a broken environment, as you say, so it is cleaner and faster to compile to simply pick one and assert the condition we actually need, no?
– Acorn
Nov 22 '18 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 '18 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 '18 at 13:31
add a comment |
Use std::size_t
. The unsigned integer std::map::size_type
won't be bigger than std::size_t
and will, in practice, be the same type.
If you want to be sure, assert it:
static_assert(std::is_same_v<
std::size_t,
std::map<std::string, std::size_t>::size_type
>);
add a comment |
All C++ implementations in the wild I have used use the same size type for all maps.
So;
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);
this just forces a compilation error if the (reasonable) assumption fails.
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 '18 at 13:44
add a comment |
The only way to break the circular dependency is to use a specific type. I recommend that you simply make map_index
be a std::size_t
- C++ strongly implies that a std::size_t
will be assignable to the map::size_type
.
add a comment |
But are you sure that the size_type
of a std::map
depends from the key/value types?
If so, I don't see a way to get it.
But the size_type
shouldn't depends from key/value types and usually is std::size_t
.
I suggest
using Index0 = typename std::map<std::string, std::size_t>::size_type;
using mapIndex = typename std::map<std::string, Index0>::size_type;
You can check you've gotten the right type with
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
1
The compiler has no way to know that the map's size type is always the same - as far as it's concerned, there could legitimately be a specialization that's different.
– Toby Speight
Nov 22 '18 at 12:53
@TobySpeight Yes, that is exactly what prompted me to ask this question. It is that "usually the same as size_t" clause from the C++ map documentation that really got me thinking about this.
– vallismortis
Nov 22 '18 at 12:59
1
@vallismortis - from theoretical point of view, you're right (as far I know). I don't see a way to break the circular dependency but addingstatic_assert( std::is_same_v<Index0, mapIndex>, "no right type");
you can check that the selected type is the right one.
– max66
Nov 22 '18 at 13:04
1
@TobySpeight - you're right (as far I know); but through astatic_assert()
(see my modified answer) we can check if we have gotten the right type.
– max66
Nov 22 '18 at 13:06
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53431281%2fstdmapsize-type-for-a-stdmap-whose-value-type-is-its-own-size-type%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
What you are looking for is, generally speaking, impossible.
It's conceivable (though far-fetched) that std::map<int, long>::size_type
is int
and std::map<int, int>::size_type
is long
(and similarly for other integer types), in which case there is no possible way to satisfy std::map<int, T>::size_type
being T
.
Conversely, it could be that std::map<int, T>::size_type
is defined as T
for all T
, in which case there is no unique T
satisfying your "requirement".
As mentioned by several answers (and your own reference link), in practice it's unlikely to be anything else than size_t
.
This is the answer I was looking for, it just isn't the one I was hoping for. The specific examples you provide illustrate the problem perfectly.
– vallismortis
Nov 22 '18 at 13:27
add a comment |
What you are looking for is, generally speaking, impossible.
It's conceivable (though far-fetched) that std::map<int, long>::size_type
is int
and std::map<int, int>::size_type
is long
(and similarly for other integer types), in which case there is no possible way to satisfy std::map<int, T>::size_type
being T
.
Conversely, it could be that std::map<int, T>::size_type
is defined as T
for all T
, in which case there is no unique T
satisfying your "requirement".
As mentioned by several answers (and your own reference link), in practice it's unlikely to be anything else than size_t
.
This is the answer I was looking for, it just isn't the one I was hoping for. The specific examples you provide illustrate the problem perfectly.
– vallismortis
Nov 22 '18 at 13:27
add a comment |
What you are looking for is, generally speaking, impossible.
It's conceivable (though far-fetched) that std::map<int, long>::size_type
is int
and std::map<int, int>::size_type
is long
(and similarly for other integer types), in which case there is no possible way to satisfy std::map<int, T>::size_type
being T
.
Conversely, it could be that std::map<int, T>::size_type
is defined as T
for all T
, in which case there is no unique T
satisfying your "requirement".
As mentioned by several answers (and your own reference link), in practice it's unlikely to be anything else than size_t
.
What you are looking for is, generally speaking, impossible.
It's conceivable (though far-fetched) that std::map<int, long>::size_type
is int
and std::map<int, int>::size_type
is long
(and similarly for other integer types), in which case there is no possible way to satisfy std::map<int, T>::size_type
being T
.
Conversely, it could be that std::map<int, T>::size_type
is defined as T
for all T
, in which case there is no unique T
satisfying your "requirement".
As mentioned by several answers (and your own reference link), in practice it's unlikely to be anything else than size_t
.
answered Nov 22 '18 at 13:24
Max LanghofMax Langhof
12.3k22241
12.3k22241
This is the answer I was looking for, it just isn't the one I was hoping for. The specific examples you provide illustrate the problem perfectly.
– vallismortis
Nov 22 '18 at 13:27
add a comment |
This is the answer I was looking for, it just isn't the one I was hoping for. The specific examples you provide illustrate the problem perfectly.
– vallismortis
Nov 22 '18 at 13:27
This is the answer I was looking for, it just isn't the one I was hoping for. The specific examples you provide illustrate the problem perfectly.
– vallismortis
Nov 22 '18 at 13:27
This is the answer I was looking for, it just isn't the one I was hoping for. The specific examples you provide illustrate the problem perfectly.
– vallismortis
Nov 22 '18 at 13:27
add a comment |
size_t
should be good enough for such case.
But if you insist, you can do like this:
#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;
}
It will run recursively on GetSizeType
, the recursive call will stop upon
- reaching the recursive call depth limitation (there will be no member
type
in this case), or - finding a specialization of
std::map
of which themapped_type
andsize_type
is identical (the membertype
aliasessize_type
).
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 '18 at 13:02
1
i dont completely agree with " You will run out of memory before running out of size_t.". Something likemy_map.size() * 2;
is a sensible operation that can overflow long before you run out of memory
– user463035818
Nov 22 '18 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 '18 at 13:07
1
@user463035818 - in the context set by the question, there's no arithmetic involved - the result ofsize()
is simply being used as an opaque identifier.
– Toby Speight
Nov 22 '18 at 13:08
1
@vallismortis What do you mean by "more extreme cases"? If you usestd::size_t
, there is no way it won't work where another type would, because that should be able to address even objects of size 1.
– Acorn
Nov 22 '18 at 13:22
|
show 5 more comments
size_t
should be good enough for such case.
But if you insist, you can do like this:
#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;
}
It will run recursively on GetSizeType
, the recursive call will stop upon
- reaching the recursive call depth limitation (there will be no member
type
in this case), or - finding a specialization of
std::map
of which themapped_type
andsize_type
is identical (the membertype
aliasessize_type
).
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 '18 at 13:02
1
i dont completely agree with " You will run out of memory before running out of size_t.". Something likemy_map.size() * 2;
is a sensible operation that can overflow long before you run out of memory
– user463035818
Nov 22 '18 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 '18 at 13:07
1
@user463035818 - in the context set by the question, there's no arithmetic involved - the result ofsize()
is simply being used as an opaque identifier.
– Toby Speight
Nov 22 '18 at 13:08
1
@vallismortis What do you mean by "more extreme cases"? If you usestd::size_t
, there is no way it won't work where another type would, because that should be able to address even objects of size 1.
– Acorn
Nov 22 '18 at 13:22
|
show 5 more comments
size_t
should be good enough for such case.
But if you insist, you can do like this:
#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;
}
It will run recursively on GetSizeType
, the recursive call will stop upon
- reaching the recursive call depth limitation (there will be no member
type
in this case), or - finding a specialization of
std::map
of which themapped_type
andsize_type
is identical (the membertype
aliasessize_type
).
size_t
should be good enough for such case.
But if you insist, you can do like this:
#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;
}
It will run recursively on GetSizeType
, the recursive call will stop upon
- reaching the recursive call depth limitation (there will be no member
type
in this case), or - finding a specialization of
std::map
of which themapped_type
andsize_type
is identical (the membertype
aliasessize_type
).
edited Nov 22 '18 at 15:28
answered Nov 22 '18 at 13:01
felixfelix
1,510314
1,510314
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 '18 at 13:02
1
i dont completely agree with " You will run out of memory before running out of size_t.". Something likemy_map.size() * 2;
is a sensible operation that can overflow long before you run out of memory
– user463035818
Nov 22 '18 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 '18 at 13:07
1
@user463035818 - in the context set by the question, there's no arithmetic involved - the result ofsize()
is simply being used as an opaque identifier.
– Toby Speight
Nov 22 '18 at 13:08
1
@vallismortis What do you mean by "more extreme cases"? If you usestd::size_t
, there is no way it won't work where another type would, because that should be able to address even objects of size 1.
– Acorn
Nov 22 '18 at 13:22
|
show 5 more comments
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 '18 at 13:02
1
i dont completely agree with " You will run out of memory before running out of size_t.". Something likemy_map.size() * 2;
is a sensible operation that can overflow long before you run out of memory
– user463035818
Nov 22 '18 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 '18 at 13:07
1
@user463035818 - in the context set by the question, there's no arithmetic involved - the result ofsize()
is simply being used as an opaque identifier.
– Toby Speight
Nov 22 '18 at 13:08
1
@vallismortis What do you mean by "more extreme cases"? If you usestd::size_t
, there is no way it won't work where another type would, because that should be able to address even objects of size 1.
– Acorn
Nov 22 '18 at 13:22
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 '18 at 13:02
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 '18 at 13:02
1
1
i dont completely agree with " You will run out of memory before running out of size_t.". Something like
my_map.size() * 2;
is a sensible operation that can overflow long before you run out of memory– user463035818
Nov 22 '18 at 13:06
i dont completely agree with " You will run out of memory before running out of size_t.". Something like
my_map.size() * 2;
is a sensible operation that can overflow long before you run out of memory– user463035818
Nov 22 '18 at 13:06
2
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 '18 at 13:07
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 '18 at 13:07
1
1
@user463035818 - in the context set by the question, there's no arithmetic involved - the result of
size()
is simply being used as an opaque identifier.– Toby Speight
Nov 22 '18 at 13:08
@user463035818 - in the context set by the question, there's no arithmetic involved - the result of
size()
is simply being used as an opaque identifier.– Toby Speight
Nov 22 '18 at 13:08
1
1
@vallismortis What do you mean by "more extreme cases"? If you use
std::size_t
, there is no way it won't work where another type would, because that should be able to address even objects of size 1.– Acorn
Nov 22 '18 at 13:22
@vallismortis What do you mean by "more extreme cases"? If you use
std::size_t
, there is no way it won't work where another type would, because that should be able to address even objects of size 1.– Acorn
Nov 22 '18 at 13:22
|
show 5 more comments
Disclaimer: this solution is pretty dumb. We're just going to solve the equation by repeatedly (typically once) trying to instantiate std::map
until we find one that has the requested key and its own size_type
as value.
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;
If the metafunction can't find such a map, it will either error out because type
ends up defined to itself, or break the recursion limit.
Both recursive solutions shown are cool, but I am unsure why one would use this. It still does not guarantee you will find one that works in a broken environment, as you say, so it is cleaner and faster to compile to simply pick one and assert the condition we actually need, no?
– Acorn
Nov 22 '18 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 '18 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 '18 at 13:31
add a comment |
Disclaimer: this solution is pretty dumb. We're just going to solve the equation by repeatedly (typically once) trying to instantiate std::map
until we find one that has the requested key and its own size_type
as value.
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;
If the metafunction can't find such a map, it will either error out because type
ends up defined to itself, or break the recursion limit.
Both recursive solutions shown are cool, but I am unsure why one would use this. It still does not guarantee you will find one that works in a broken environment, as you say, so it is cleaner and faster to compile to simply pick one and assert the condition we actually need, no?
– Acorn
Nov 22 '18 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 '18 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 '18 at 13:31
add a comment |
Disclaimer: this solution is pretty dumb. We're just going to solve the equation by repeatedly (typically once) trying to instantiate std::map
until we find one that has the requested key and its own size_type
as value.
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;
If the metafunction can't find such a map, it will either error out because type
ends up defined to itself, or break the recursion limit.
Disclaimer: this solution is pretty dumb. We're just going to solve the equation by repeatedly (typically once) trying to instantiate std::map
until we find one that has the requested key and its own size_type
as value.
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;
If the metafunction can't find such a map, it will either error out because type
ends up defined to itself, or break the recursion limit.
answered Nov 22 '18 at 13:02
QuentinQuentin
47.1k692148
47.1k692148
Both recursive solutions shown are cool, but I am unsure why one would use this. It still does not guarantee you will find one that works in a broken environment, as you say, so it is cleaner and faster to compile to simply pick one and assert the condition we actually need, no?
– Acorn
Nov 22 '18 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 '18 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 '18 at 13:31
add a comment |
Both recursive solutions shown are cool, but I am unsure why one would use this. It still does not guarantee you will find one that works in a broken environment, as you say, so it is cleaner and faster to compile to simply pick one and assert the condition we actually need, no?
– Acorn
Nov 22 '18 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 '18 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 '18 at 13:31
Both recursive solutions shown are cool, but I am unsure why one would use this. It still does not guarantee you will find one that works in a broken environment, as you say, so it is cleaner and faster to compile to simply pick one and assert the condition we actually need, no?
– Acorn
Nov 22 '18 at 13:24
Both recursive solutions shown are cool, but I am unsure why one would use this. It still does not guarantee you will find one that works in a broken environment, as you say, so it is cleaner and faster to compile to simply pick one and assert the condition we actually need, no?
– Acorn
Nov 22 '18 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 '18 at 13:27
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 '18 at 13:27
1
1
@Quentin same here, cheers.
– felix
Nov 22 '18 at 13:31
@Quentin same here, cheers.
– felix
Nov 22 '18 at 13:31
add a comment |
Use std::size_t
. The unsigned integer std::map::size_type
won't be bigger than std::size_t
and will, in practice, be the same type.
If you want to be sure, assert it:
static_assert(std::is_same_v<
std::size_t,
std::map<std::string, std::size_t>::size_type
>);
add a comment |
Use std::size_t
. The unsigned integer std::map::size_type
won't be bigger than std::size_t
and will, in practice, be the same type.
If you want to be sure, assert it:
static_assert(std::is_same_v<
std::size_t,
std::map<std::string, std::size_t>::size_type
>);
add a comment |
Use std::size_t
. The unsigned integer std::map::size_type
won't be bigger than std::size_t
and will, in practice, be the same type.
If you want to be sure, assert it:
static_assert(std::is_same_v<
std::size_t,
std::map<std::string, std::size_t>::size_type
>);
Use std::size_t
. The unsigned integer std::map::size_type
won't be bigger than std::size_t
and will, in practice, be the same type.
If you want to be sure, assert it:
static_assert(std::is_same_v<
std::size_t,
std::map<std::string, std::size_t>::size_type
>);
answered Nov 22 '18 at 13:04
AcornAcorn
6,71411442
6,71411442
add a comment |
add a comment |
All C++ implementations in the wild I have used use the same size type for all maps.
So;
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);
this just forces a compilation error if the (reasonable) assumption fails.
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 '18 at 13:44
add a comment |
All C++ implementations in the wild I have used use the same size type for all maps.
So;
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);
this just forces a compilation error if the (reasonable) assumption fails.
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 '18 at 13:44
add a comment |
All C++ implementations in the wild I have used use the same size type for all maps.
So;
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);
this just forces a compilation error if the (reasonable) assumption fails.
All C++ implementations in the wild I have used use the same size type for all maps.
So;
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);
this just forces a compilation error if the (reasonable) assumption fails.
edited Nov 22 '18 at 13:45
vallismortis
3,743104366
3,743104366
answered Nov 22 '18 at 13:33
Yakk - Adam NevraumontYakk - Adam Nevraumont
190k21200385
190k21200385
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 '18 at 13:44
add a comment |
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 '18 at 13:44
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 '18 at 13:44
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 '18 at 13:44
add a comment |
The only way to break the circular dependency is to use a specific type. I recommend that you simply make map_index
be a std::size_t
- C++ strongly implies that a std::size_t
will be assignable to the map::size_type
.
add a comment |
The only way to break the circular dependency is to use a specific type. I recommend that you simply make map_index
be a std::size_t
- C++ strongly implies that a std::size_t
will be assignable to the map::size_type
.
add a comment |
The only way to break the circular dependency is to use a specific type. I recommend that you simply make map_index
be a std::size_t
- C++ strongly implies that a std::size_t
will be assignable to the map::size_type
.
The only way to break the circular dependency is to use a specific type. I recommend that you simply make map_index
be a std::size_t
- C++ strongly implies that a std::size_t
will be assignable to the map::size_type
.
answered Nov 22 '18 at 13:00
Toby SpeightToby Speight
17.6k134469
17.6k134469
add a comment |
add a comment |
But are you sure that the size_type
of a std::map
depends from the key/value types?
If so, I don't see a way to get it.
But the size_type
shouldn't depends from key/value types and usually is std::size_t
.
I suggest
using Index0 = typename std::map<std::string, std::size_t>::size_type;
using mapIndex = typename std::map<std::string, Index0>::size_type;
You can check you've gotten the right type with
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
1
The compiler has no way to know that the map's size type is always the same - as far as it's concerned, there could legitimately be a specialization that's different.
– Toby Speight
Nov 22 '18 at 12:53
@TobySpeight Yes, that is exactly what prompted me to ask this question. It is that "usually the same as size_t" clause from the C++ map documentation that really got me thinking about this.
– vallismortis
Nov 22 '18 at 12:59
1
@vallismortis - from theoretical point of view, you're right (as far I know). I don't see a way to break the circular dependency but addingstatic_assert( std::is_same_v<Index0, mapIndex>, "no right type");
you can check that the selected type is the right one.
– max66
Nov 22 '18 at 13:04
1
@TobySpeight - you're right (as far I know); but through astatic_assert()
(see my modified answer) we can check if we have gotten the right type.
– max66
Nov 22 '18 at 13:06
add a comment |
But are you sure that the size_type
of a std::map
depends from the key/value types?
If so, I don't see a way to get it.
But the size_type
shouldn't depends from key/value types and usually is std::size_t
.
I suggest
using Index0 = typename std::map<std::string, std::size_t>::size_type;
using mapIndex = typename std::map<std::string, Index0>::size_type;
You can check you've gotten the right type with
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
1
The compiler has no way to know that the map's size type is always the same - as far as it's concerned, there could legitimately be a specialization that's different.
– Toby Speight
Nov 22 '18 at 12:53
@TobySpeight Yes, that is exactly what prompted me to ask this question. It is that "usually the same as size_t" clause from the C++ map documentation that really got me thinking about this.
– vallismortis
Nov 22 '18 at 12:59
1
@vallismortis - from theoretical point of view, you're right (as far I know). I don't see a way to break the circular dependency but addingstatic_assert( std::is_same_v<Index0, mapIndex>, "no right type");
you can check that the selected type is the right one.
– max66
Nov 22 '18 at 13:04
1
@TobySpeight - you're right (as far I know); but through astatic_assert()
(see my modified answer) we can check if we have gotten the right type.
– max66
Nov 22 '18 at 13:06
add a comment |
But are you sure that the size_type
of a std::map
depends from the key/value types?
If so, I don't see a way to get it.
But the size_type
shouldn't depends from key/value types and usually is std::size_t
.
I suggest
using Index0 = typename std::map<std::string, std::size_t>::size_type;
using mapIndex = typename std::map<std::string, Index0>::size_type;
You can check you've gotten the right type with
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
But are you sure that the size_type
of a std::map
depends from the key/value types?
If so, I don't see a way to get it.
But the size_type
shouldn't depends from key/value types and usually is std::size_t
.
I suggest
using Index0 = typename std::map<std::string, std::size_t>::size_type;
using mapIndex = typename std::map<std::string, Index0>::size_type;
You can check you've gotten the right type with
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
edited Nov 22 '18 at 13:10
answered Nov 22 '18 at 12:49
max66max66
39.6k74575
39.6k74575
1
The compiler has no way to know that the map's size type is always the same - as far as it's concerned, there could legitimately be a specialization that's different.
– Toby Speight
Nov 22 '18 at 12:53
@TobySpeight Yes, that is exactly what prompted me to ask this question. It is that "usually the same as size_t" clause from the C++ map documentation that really got me thinking about this.
– vallismortis
Nov 22 '18 at 12:59
1
@vallismortis - from theoretical point of view, you're right (as far I know). I don't see a way to break the circular dependency but addingstatic_assert( std::is_same_v<Index0, mapIndex>, "no right type");
you can check that the selected type is the right one.
– max66
Nov 22 '18 at 13:04
1
@TobySpeight - you're right (as far I know); but through astatic_assert()
(see my modified answer) we can check if we have gotten the right type.
– max66
Nov 22 '18 at 13:06
add a comment |
1
The compiler has no way to know that the map's size type is always the same - as far as it's concerned, there could legitimately be a specialization that's different.
– Toby Speight
Nov 22 '18 at 12:53
@TobySpeight Yes, that is exactly what prompted me to ask this question. It is that "usually the same as size_t" clause from the C++ map documentation that really got me thinking about this.
– vallismortis
Nov 22 '18 at 12:59
1
@vallismortis - from theoretical point of view, you're right (as far I know). I don't see a way to break the circular dependency but addingstatic_assert( std::is_same_v<Index0, mapIndex>, "no right type");
you can check that the selected type is the right one.
– max66
Nov 22 '18 at 13:04
1
@TobySpeight - you're right (as far I know); but through astatic_assert()
(see my modified answer) we can check if we have gotten the right type.
– max66
Nov 22 '18 at 13:06
1
1
The compiler has no way to know that the map's size type is always the same - as far as it's concerned, there could legitimately be a specialization that's different.
– Toby Speight
Nov 22 '18 at 12:53
The compiler has no way to know that the map's size type is always the same - as far as it's concerned, there could legitimately be a specialization that's different.
– Toby Speight
Nov 22 '18 at 12:53
@TobySpeight Yes, that is exactly what prompted me to ask this question. It is that "usually the same as size_t" clause from the C++ map documentation that really got me thinking about this.
– vallismortis
Nov 22 '18 at 12:59
@TobySpeight Yes, that is exactly what prompted me to ask this question. It is that "usually the same as size_t" clause from the C++ map documentation that really got me thinking about this.
– vallismortis
Nov 22 '18 at 12:59
1
1
@vallismortis - from theoretical point of view, you're right (as far I know). I don't see a way to break the circular dependency but adding
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
you can check that the selected type is the right one.– max66
Nov 22 '18 at 13:04
@vallismortis - from theoretical point of view, you're right (as far I know). I don't see a way to break the circular dependency but adding
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");
you can check that the selected type is the right one.– max66
Nov 22 '18 at 13:04
1
1
@TobySpeight - you're right (as far I know); but through a
static_assert()
(see my modified answer) we can check if we have gotten the right type.– max66
Nov 22 '18 at 13:06
@TobySpeight - you're right (as far I know); but through a
static_assert()
(see my modified answer) we can check if we have gotten the right type.– max66
Nov 22 '18 at 13:06
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53431281%2fstdmapsize-type-for-a-stdmap-whose-value-type-is-its-own-size-type%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
minor nitpick: I think you have the last sentence the wrong way around. To know what is
size_type
you first need to tell what is thevalue_type
not the other way around. Once you know the type of the map, getting itssize_type
is trivial– user463035818
Nov 22 '18 at 12:44
@user463035818 The problem seems to be that the
size_type
is a part ofvalue_type
for the OP.– Some programmer dude
Nov 22 '18 at 12:46
5
You have a circular dependency. Why can't you use
size_t
(which is whatsize_type
normally will be anyway)?– Some programmer dude
Nov 22 '18 at 12:47
can you explain why you want that? afaik
map::size_type
is just atypedef
aliasing always the same type anyhow– user463035818
Nov 22 '18 at 12:47
3
std::map<K, V>::size_type
is most likely completely independent of bothK
andV
. If you really care, you canstatic_assert(std::is_same_v<Map::size_type, Map::mapped_type>, "Unexpected size_type")
– Caleth
Nov 22 '18 at 12:59