dynamic_cast из не шаблонного класса в шаблонный подкласс - PullRequest
0 голосов
/ 28 февраля 2020

У меня есть не шаблонный класс N C и производный шаблонный класс T C. Я хочу привести указатель к N C, который потенциально является указателем на экземпляр T C, на указатель T C. Фактические типы шаблона ограничены, например, bool, int и string.

class NC {
...
}

template <typename T>
class TC: public NC {
private:
    T value;
public:
    ...
    void setValue(T value) {
        this->value = value;
    }
}

class UserValueProvider {
public:
    int getValue() const { return 5; }
    bool getValue() const { return true; }
    string getValue() const { return "foobar"; }
}

void setUserValue(UserValueProvider *uvp, NC *obj) {
    auto tobj = dynamic_cast< ? >(obj);        // what goes here?
    if(tobj)
        tobj->setValue(uvp->getValue());
}

Очевидным решением будет выполнить 3 динамических приведения c (для int, bool и string) и вызвать setValue специализированного экземпляра. Тем не менее, я задаюсь вопросом, может ли быть другое решение, поскольку чем больше специализаций возможно, тем больше динамических бросков c потребуется, и с большей вероятностью забудется одна специализация.

1 Ответ

0 голосов
/ 28 февраля 2020

Одно из решений здесь - перевернуть вызов и использовать виртуальную функцию. Но сначала давайте перепишем UserValueProvider::getValue, поскольку перегрузка только для возвращаемых типов запрещена.

class UserValueProvider {
    template <class T> struct tag { };
    int getValue(tag<int>) const { return 5; }
    bool getValue(tag<bool>) const { return true; }
    std::string getValue(tag<std::string>) const { return "foobar"; }

public:
    template <class T>
    T getValue() const {
        return getValue(tag<T>{});
    }
};

Теперь мы можем вызвать uvp.getValue<T>(), чтобы получить соответствующее значение. Затем добавьте виртуальную функцию к NC и ее производным классам:

class NC {
public:
    virtual void setValueFrom(UserValueProvider &uvp) = 0;
};

template <typename T>
class TC: public NC {
private:
    T value;
public:
    void setValue(T value) {
        this->value = value;
    }

    void setValueFrom(UserValueProvider &uvp) override {
        setValue(uvp.getValue<T>());
    }
};

И вуаля, вы можете просто передать свой UserValueProvider своему стертому типу NC, и он будет отправляться правильно.

void setUserValue(UserValueProvider *uvp, NC *obj) {
    obj->setValueFrom(*uvp);
}

Посмотреть в прямом эфире на Wandbox

...