Проектирование системы литья полиморфного типа c - PullRequest
0 голосов
/ 20 апреля 2020

Я пишу переводчик и в настоящее время работаю над приведением типов. Я опустил код, который не имеет отношения к вопросу.

Каждое значение имеет набор методов приведения к разным типам. Если значение не поддерживает приведение к указанному типу c, оно возвращает nullptr. Затем в подклассах вы можете переопределить приведение, например, IntValue к FloatValue, но наоборот ограничено, поэтому мы используем базовую версию.

class Value : public Node {
public:
    virtual IntValue* cast(IntValue* value) { return nullptr; }
    virtual FloatValue* cast(FloatValue* value) { return nullptr; }
    virtual StringValue* cast(StringValue* value) { return nullptr; }
    virtual BoolValue* cast(BoolValue* value) { return nullptr; }

    virtual Value* add(Value* other) { throw std::runtime_error("Add operation is not supported for type <...>"); }
    ...
};

Класс Generi c используется для уменьшения количество шаблонного кода для каждого конкретного значения. Generi c logi c для каждой операции, например «add», выглядит следующим образом: приведение операнда rhs к типу lhs, если приведение не поддерживается, приведение lhs к типу rhs. Я могу справиться с первым случаем, но не могу понять, как получить конкретный тип для операнда rhs.

template <typename ValueType, typename T>
class GenericValue : public Value {
public:

    Value* add(Value* other) override {
        std::unique_ptr<ValueType> rhs(other->cast(self()));

        if(rhs){
            return self()->add(rhs.get());
        }          

        ... How to cast this object to other type
    }

    inline ValueType* self() { return static_cast<ValueType*>(this); }

    ...
};

class IntValue : public GenericValue<IntValue, int>, public Copyable<IntValue> {
public:
    IntValue* cast(IntValue* value) override { return copy(); }
    FloatValue* cast(FloatValue* value) override { return new FloatValue((float)value_); }

    Value* IntValue::add(IntValue* other){
        return new IntValue(value_ + other->value_);
    }
    ...
};

Так, например, если я вызову add для чисел с плавающей точкой и целых чисел, это приведет к тому, что последние с плавающей точкой вызовут метод add из FloatValue. Но если мы поменяем их местами, первоначально float получит целое число. Тогда приведение не будет выполнено, потому что мой язык не поддерживает такие операции, и интерпретатор попытается преобразовать целое число в число с плавающей точкой. Но, как вы можете заметить, это значение с плавающей точкой относится к типу Value, поэтому я не уверен, как получить эту информацию, избегая написания стандартного кода.

Одним из решений, которое будет работать с коммутативными операциями, является замена операндов. и вызовите rhs-> add (lhs). Но я хочу более общий c способ сделать это.

Я изо всех сил пытаюсь создать рабочий пример, потому что кода так много. Я сделал все возможное, чтобы упростить проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...