Home > OS >  Accessing variable template using decltype
Accessing variable template using decltype

Time:12-05

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;
}

Godbolt

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.

  • Related