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_typeyou first need to tell what is thevalue_typenot the other way around. Once you know the type of the map, getting itssize_typeis trivial
– user463035818
Nov 22 at 12:44
@user463035818 The problem seems to be that thesize_typeis a part ofvalue_typefor 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_typenormally will be anyway)?
– Some programmer dude
Nov 22 at 12:47
can you explain why you want that? afaikmap::size_typeis just atypedefaliasing always the same type anyhow
– user463035818
Nov 22 at 12:47
3
std::map<K, V>::size_typeis most likely completely independent of bothKandV. 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_typeyou first need to tell what is thevalue_typenot the other way around. Once you know the type of the map, getting itssize_typeis trivial
– user463035818
Nov 22 at 12:44
@user463035818 The problem seems to be that thesize_typeis a part ofvalue_typefor 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_typenormally will be anyway)?
– Some programmer dude
Nov 22 at 12:47
can you explain why you want that? afaikmap::size_typeis just atypedefaliasing always the same type anyhow
– user463035818
Nov 22 at 12:47
3
std::map<K, V>::size_typeis most likely completely independent of bothKandV. 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_typeyou first need to tell what is thevalue_typenot the other way around. Once you know the type of the map, getting itssize_typeis trivial
– user463035818
Nov 22 at 12:44
@user463035818 The problem seems to be that thesize_typeis a part ofvalue_typefor 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_typenormally will be anyway)?
– Some programmer dude
Nov 22 at 12:47
can you explain why you want that? afaikmap::size_typeis just atypedefaliasing always the same type anyhow
– user463035818
Nov 22 at 12:47
3
std::map<K, V>::size_typeis most likely completely independent of bothKandV. 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
typein this case), or - finding a specialization of
std::mapof which themapped_typeandsize_typeis identical (the membertypealiasessize_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
typein this case), or - finding a specialization of
std::mapof which themapped_typeandsize_typeis identical (the membertypealiasessize_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
typein this case), or - finding a specialization of
std::mapof which themapped_typeandsize_typeis identical (the membertypealiasessize_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
typein this case), or - finding a specialization of
std::mapof which themapped_typeandsize_typeis identical (the membertypealiasessize_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
typein this case), or - finding a specialization of
std::mapof which themapped_typeandsize_typeis identical (the membertypealiasessize_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_typeyou first need to tell what is thevalue_typenot the other way around. Once you know the type of the map, getting itssize_typeis trivial– user463035818
Nov 22 at 12:44
@user463035818 The problem seems to be that the
size_typeis a part ofvalue_typefor 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_typenormally will be anyway)?– Some programmer dude
Nov 22 at 12:47
can you explain why you want that? afaik
map::size_typeis just atypedefaliasing always the same type anyhow– user463035818
Nov 22 at 12:47
3
std::map<K, V>::size_typeis most likely completely independent of bothKandV. 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