6

Consider the following code:

#include <iostream>
#include <typeinfo>
#include <map>


int main(int argc, const char* argv[]) {
    typedef std::map<int,float> testmap;
    typedef std::map<int,float> testmap2;
    typedef std::map<typename testmap::value_type::first_type, typename testmap::value_type::second_type> rebuiltMap;
    std::cout << "map samenes: " << std::is_same<testmap, rebuiltMap>::value << "\n";
    std::cout << "map samenes: " << std::is_same<testmap, testmap2>::value << "\n";
    std::cout << "original map type name " << typeid(testmap).name() << "\n";
    std::cout << "same     map type name " << typeid(testmap2).name() << "\n";
    std::cout << "rebuilt  map type name " << typeid(rebuiltMap).name() << "\n";
    std::cout << "original map valuetype " << typeid(testmap::value_type).name() << "\n";
    std::cout << "rebuilt  map valuetype " << typeid(rebuiltMap::value_type).name() << "\n";
}

This produces the following output:

map samenes: 0
map samenes: 1
original map type name St3mapIifSt4lessIiESaISt4pairIKifEEE
same     map type name St3mapIifSt4lessIiESaISt4pairIKifEEE
rebuilt  map type name St3mapIKifSt4lessIS0_ESaISt4pairIS0_fEEE
original map valuetype St4pairIKifE
rebuilt  map valuetype St4pairIKifE

Why is the "rebuilt" map type different from the simple map type, although both have the same value_type? Background: i want to test if a container containing pairs is a map or not with a construct like

std::is_same<std::map<typename Container::value_type::first_type,
                      typename Container::value_type::second_type>,
             Container>::value
  • Demangled type names: `std::map, std::allocator > >` and `std::map, std::allocator > >` – 273K Nov 15 '19 at 15:56

3 Answers3

5

testmap::value_type::first_type is const int rather than int.

You could use testmap::key_type instead to get the correct type. Based on the pair type, it is not possible to distinguish const and non-const key type. That said, a const key would not satisfy the requirements of std::map, so you could simply assume that it is non-const and remove const from testmap::value_type::first_type.

eerorika
  • 232,697
  • 12
  • 197
  • 326
5

This is because std::map::value_type is std::pair<const Key, Value>, not std::pair<Key, Value>. The reason for that is you are never allowed to modify the key of a pair that is in the map.

To get the rebuilt map to be the same using value_type::first_type you need to remove that const using std::remove_const_t like

typedef std::map<std::remove_const_t<typename testmap::value_type::first_type>, typename testmap::value_type::second_type> rebuiltMap;
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

As others have pointed out, this:

std::map<typename testmap::value_type::first_type, typename testmap::value_type::second_type>

… is not quite right, because a const is automatically added to the key for use in value_type, and this results in a distinct type.

That's what GCC's mangled name is telling you:

St3mapIKifSt4lessIS0_ESaISt4pairIS0_fEEE
//     ^ const

My recommendation is to use the convenient type aliases provided by map:

std::map<typename testmap::key_type, typename testmap::mapped_type>

… or, for a complete solution:

std::map<
   typename testmap::key_type,
   typename testmap::mapped_type,
   typename testmap::key_compare,
   typename testmap::allocator_type
>

This is, after all, what the aliases are there for.


Or just use testmap!

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Thanks, these answers solved my Problem. The key_type and mapped_type don't help in my case, because if the container is e.g. a std::list> they don't exist and the test would fail. – Dr. Jürgen Hannappel Nov 15 '19 at 15:29
  • @Dr.JürgenHannappel But that's a good thing! I'd actually suggest you just check for the presence of `mapped_type` to find out whether your container is associative, rather than the "rebuilding" trick you're doing now. Your way has too many edge cases and compromises. You cannot get back, reliably, the information "this `value_type` belongs to a map". So instead architect your template code to be based on traits and properties of types. – Lightness Races in Orbit Nov 15 '19 at 15:48