Referencing a static class in a key-value pair

126 Views Asked by At

I have defined classes that represent different operators, and made them static. I think that this would be a proper way to represent them, since it would not make sense to instantiate them.

They are declared like this

static class BinaryOperator {
        int priority;
        virtual float apply(float left, float right) = 0;
    };

static class Plus : BinaryOperator {
        float apply(float left, float right) override;
    };

static class Times : BinaryOperator {
        float apply(float left, float right) override;
    };

...

Since I have other, non-trivial operators, which can have multi-character symbols, I want to make a map<string, BinaryOperator> that would make them easy to access, like this:

const map<string, dice::BinaryOperator> dice::Calculator::str_to_op_ = {
    ("+", dice::Plus),
    ("*", dice::Times),
    ("AC", dice::AC),
}

However, when I want to create this map, I get the following error:

type name not allowed

which makes sense. However, I am looking for a way to refer to the single instances of these static classes in the map, which should theoretically allow them to be the values in my map

I've tried making pointers to these classes, but it does not seem to work / I don't know how to properly do it.

1

There are 1 best solutions below

0
Red.Wave On

Unlike java, C++ does not support inner classes. The keyword static is only applicable to objects and functions, not types. All C++ classes are static in java terms. Dynamic polymorphism is not that welcome in C++. There are usually better abstraction mechanisms available. More over function object is a very common concept on modern C++. All objects (except raw arrays and char string literals) are - by default - transferred by value. If a function needs by-reference arguments, the arguments must be marked as references in the function declaration. The official braces for initialization are curly pairs {} not round (). All in all, I can rewrite your snippet like:

struct binary_operator{
    float (*apply)(int, float, float);
    int priority;
};

float product (int, float, float);

const std::unordered _map<std::string, binary_operator> str_to_op{
    { "+",
      { [](int pri, float op1, float op2) {
           if (pri)
               return op1+op2;
           return 0;
      }}
    },

    { "*", {&product} }
};

Instead of a function pointer, you may use std::function<void(int,float,float)> as the type of binary_operator::apply for more generic and flexible code.

The outline and design of code can drastically change if you know more about what you need. You can even define your binary_operator in terms of std::variant, if you already know the full set of operators needed. This much is a reorganization of what I could read from your snippet.