0

I would like to make my app’s std::maps’ keys not be ints, but rather be more strongly typed as templated non-type enums defined as a member of a struct. The first program below shows the concept of how my app currently uses maps. 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 maps, 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.

2
  • what on earth are you trying to achieve? Commented Jul 26, 2017 at 19:43
  • be more strongly typed in a large program translates into greater program clarity, better error checking and in general easier code maintenance. Commented Jul 26, 2017 at 20:02

1 Answer 1

1
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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.