简体   繁体   中英

std::map with key as templated structs with enum member

I would like to make my app's std::map s' keys not be int s, but rather be more strongly typed as templated non-type enum s defined as a member of a struct . The first program below shows the concept of how my app currently uses map s. It compiles and runs ok.

#include <map>

template< int >
struct NummedMap
{
  typedef std::map< int, NummedMap > NumableMap;

  NummedMap() {}

  NumableMap numableMap;
};

int main()
{
  NummedMap< 3 > numableMap3;
  NummedMap< 4 > numableMap4;
  numableMap3.numableMap[ 3 ] = numableMap3;
  numableMap4.numableMap[ 4 ] = numableMap4;

  return 0;
}

The second program shows how I would like to program my app's map s, but I am missing some concepts regarding non-type templates and why an < enum EnumT > is different from a POD int .

#include <map>

struct Enums1 // a struct containing one kind scoped enums
{ 
  enum class Action
  {
    AAAA,
    BBBB
  };
};

struct Enums2 // a struct containing another kind scoped enums
{
  enum class Action
  {
    CCCC,
    DDDD
  };
};

template< enum EnumT >
struct EnummedMap // a struct containing a map whose key is non-type templateable
{
  typedef std::map< EnumT, EnummedMap > EnumableMap; // error C2065: 'EnumT': undeclared identifier

  EnummedMap() {}

  EnumableMap enumableMap;
};

int main()
{
  EnummedMap< Enums1::Action > enummedMap1; // error C2993: illegal type for non-type template parameter 
  EnummedMap< Enums2::Action > enummedMap2; // error C2993: illegal type for non-type template parameter 
  enummedMap1.enumableMap[ Enums1::Action::AAAA ] = enummedMap1; // error C2678: binary '[': no operator found which takes a left-hand operand of type
  enummedMap2.enumableMap[ Enums2::Action::CCCC ] = enummedMap2; // error C2678: binary '[': no operator found which takes a left-hand operand of type

  return 0;
}

I don't understand why EnumableMap 's key is undeclared, or why for example Enums1::Action does not function roughly like an int key.

template< enum EnumT >
struct EnummedMap // a struct containing a map whose key is non-type templateable
{
  typedef std::map< EnumT, EnummedMap > EnumableMap; 

A non-type template parameter (in this case an old-style enum), is a single value, and by definition is not a type, but std::map expects the Key to be a type, not a value. To make this work, change "enum" to "typename":

template<typename EnumT > // << *** HERE ***
struct EnummedMap // a struct containing a map whose key is non-type templateable
{
    typedef std::map< EnumT, EnummedMap > EnumableMap; 
    EnummedMap() {}

    EnumableMap enumableMap;
};

However, this allows for non-enum types. If you want to prevent all uses EXCEPT for enum types, you can use a static_assert:

#include <type_traits>
//...
template<typename EnumT>
struct EnummedMap 
{
    static_assert(std::is_enum_v<EnumT>); // c++17
    //static_assert(std::is_enum<EnumT>::value, ""); // c++11

    typedef std::map< EnumT, EnummedMap > EnumableMap;
    EnummedMap() {}

    EnumableMap enumableMap;
};

Then it won't compile if a non-enum is passed as the template parameter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM