std::map::size_type for a std::map whose value_type is its own size_type
up vote
4
down vote
favorite
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
up vote
4
down vote
favorite
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 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 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 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 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 at 12:59
|
show 3 more comments
up vote
4
down vote
favorite
up vote
4
down vote
favorite
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 at 13:53
asked Nov 22 at 12:41
vallismortis
3,367103962
3,367103962
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 at 12:59
|
show 3 more comments
7 Answers
7
active
oldest
votes
up vote
1
down vote
accepted
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 at 13:27
add a comment |
up vote
5
down vote
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 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 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 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 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 at 13:22
|
show 5 more comments
up vote
4
down vote
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 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 at 13:31
add a comment |
up vote
2
down vote
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 |
up vote
2
down vote
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 at 13:44
add a comment |
up vote
1
down vote
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 |
up vote
1
down vote
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 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 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 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 at 13:06
add a comment |
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
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 at 13:27
add a comment |
up vote
1
down vote
accepted
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 at 13:27
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
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 at 13:24
Max Langhof
8,1181335
8,1181335
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 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 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 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 at 13:27
add a comment |
up vote
5
down vote
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 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 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 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 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 at 13:22
|
show 5 more comments
up vote
5
down vote
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 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 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 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 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 at 13:22
|
show 5 more comments
up vote
5
down vote
up vote
5
down vote
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 at 15:28
answered Nov 22 at 13:01
felix
1,428314
1,428314
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 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 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 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 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 at 13:22
|
show 5 more comments
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 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 at 13:06
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 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 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 at 13:22
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 at 13:02
Technical thug approach of the first order - brilliant!
– Toby Speight
Nov 22 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 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 at 13:06
2
2
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 at 13:07
@user463035818 Thanks, I have removed that part. I wrongly simplified the usage.
– felix
Nov 22 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 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 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 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 at 13:22
|
show 5 more comments
up vote
4
down vote
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 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 at 13:31
add a comment |
up vote
4
down vote
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 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 at 13:31
add a comment |
up vote
4
down vote
up vote
4
down vote
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 at 13:02
Quentin
44.1k583139
44.1k583139
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 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 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 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 at 13:27
1
@Quentin same here, cheers.
– felix
Nov 22 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 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 at 13:24
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 at 13:27
@Acorn yes. I just needed something to do while I'm doing a full rebuild ;)
– Quentin
Nov 22 at 13:27
1
1
@Quentin same here, cheers.
– felix
Nov 22 at 13:31
@Quentin same here, cheers.
– felix
Nov 22 at 13:31
add a comment |
up vote
2
down vote
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 |
up vote
2
down vote
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 |
up vote
2
down vote
up vote
2
down vote
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 at 13:04
Acorn
4,83711135
4,83711135
add a comment |
add a comment |
up vote
2
down vote
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 at 13:44
add a comment |
up vote
2
down vote
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 at 13:44
add a comment |
up vote
2
down vote
up vote
2
down vote
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 at 13:45
vallismortis
3,367103962
3,367103962
answered Nov 22 at 13:33
Yakk - Adam Nevraumont
180k19188367
180k19188367
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 at 13:44
add a comment |
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 at 13:44
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 at 13:44
I'm linking another question here because your answer seems relevant to it as well.
– vallismortis
Nov 22 at 13:44
add a comment |
up vote
1
down vote
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 |
up vote
1
down vote
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 |
up vote
1
down vote
up vote
1
down vote
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 at 13:00
Toby Speight
16.1k133965
16.1k133965
add a comment |
add a comment |
up vote
1
down vote
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 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 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 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 at 13:06
add a comment |
up vote
1
down vote
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 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 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 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 at 13:06
add a comment |
up vote
1
down vote
up vote
1
down vote
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 at 13:10
answered Nov 22 at 12:49
max66
33.7k63762
33.7k63762
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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 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 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 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 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 at 12:59