A minimized example of my code showing the problem:
#include <cassert>
#include <iostream>
#include <map>
#include <string>
template <typename T>
const std::map<std::string, T> smap;
template <>
const std::map<std::string, bool> smap<bool>{{"a", false}};
int main() {
std::map<bool, std::string> rmap{{false, "x"}};
for (const auto& [key, val] : rmap) {
std::cerr << typeid(bool).hash_code() << "\n";
std::cerr << typeid(decltype(key)).hash_code() << "\n";
std::cerr << smap<bool>.size() << "\n";
std::cerr << smap<decltype(key)>.size() << "\n";
assert((std::is_same_v<bool, decltype(key)>));
}
return 0;
}
It gives the output:
10838281452030117757
10838281452030117757
1
0
example.cpp:22: int main(): Assertion `(std::is_same_v<bool, decltype(key)>)' failed.
Why is it that I can't access the variable template using decltype
when it's referring to the same type (bool
)?
For the record I also tried to not use structured binding and using decltype on first in the pair with the same result.
However if I create an actual bool variable, like so ...
bool b;
std::cerr << settings_map<decltype(b)>.size() << "\n";
... it's working.
CodePudding user response:
decltype(key)
is const bool
, not bool
. And typeid
strips const qualifiers, so the two have the same (runtime) representation.
If the type of type or expression is cv-qualified, the result of the typeid refers to a
std::type_info
object representing the cv-unqualified type (that is,typeid(const T) == typeid(T)
).
So while typeid
treats the two types as equivalent, template expansion (and is_same_v
) does not, and you get two different maps: one for bool
and one for const bool
. Note that the assertion
assert((std::is_same_v<const bool, decltype(key)>));
succeeeds if put in place of the one in your code. To remove cv-qualifiers, use remove_cv_t
.
std::cerr << settings_map<std::remove_cv_t<decltype(key)>>.size() << "\n";
In your last snippet
bool b;
std::cerr << settings_map<decltype(b)>.size() << "\n";
The b
is not constant, so decltype(b)
is actually bool
, not const bool
.
CodePudding user response:
Keys are const
so you'll need to remove it to make the assertion pass.
assert((std::is_same_v<bool, std::remove_cv_t<decltype(key)>>));
CodePudding user response:
the value_type
is std::pair<const Key, T>
, so decltype(key)
is const bool
, not bool
and you capture it by const auto&
so it's const
anyway
typeid
remove all cvref qualifiers, that's why you get same hash_code
as a side note, hash_code
is a hash and no guaranteed on they would not collide, you can use operator==
to check type equality.