Получение шаблона извлекает значение класса из указателя базового класса - PullRequest
0 голосов
/ 21 января 2019

У меня есть инструмент, который позволяет пользователю редактировать единообразное значение переменной glsl, и мне нужно хранить все данные в std :: vector.

Поскольку все значения переменной имеют разные типы переменных (vec2, vec3, vec4, mat2 ... и т. Д.), Их хранение в одном контейнере является сложной задачей.Я решил пойти с этим подходом

class BaseData
{
    public:
};

template <typename T>
class Data: public BaseData
{
public:

    Data(TypeEnum enumType, T valueIN): value(valueIN), type(enumType)
    {

    }

    T GetValue()
    {
        return value; 
    }

    TypeEnum GetType()
    {
        return type;
    }

private:
    T value;
    TypeEnum type;
};

class Material
{
    Material(std::vector<Base*> valueVec)
    {
        for(auto i : valueVec)
        { 
            switch(i->GetType())
            {
                case BaseColor:
                    SetBaseColor(i->GetValue());//need something like this
                    break;
                case BaseTexture:
                    SetBaseTexture(i->GetValue());//need something like this
                    break;
                case EmissionColor:
                    SetEmissionFactor(i->GetValue());//need something like this
                    break;
                case EmissionTexture:
                    SetEmissionTexture(i->GetValue());//need something like this
                    break;
                case Material_nProps_NormalTexture:
                    SetNormalMap(i->GetValue());//need something like this
            } 
        }
    }
}

int main()
{
    std::vector<BaseData*> uniformValue;

    uniformValue.push_back(new Data(BaseColor, glm::vec4(1,2,3,4)));
    uniformValue.push_back(new Data(BaseTexture, 0));
    uniformValue.push_back(new Data(EmissionColor, glm::vec3(1,1,1)));    
    uniformValue.push_back(new Data(BaseTexture, 1));

    Material PBR(uniformValue);
}

, но проблема в том, как теперь, как мне получить значение из базового указателя, не приводя его к правильному указателю производного типа?

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Если вы не хотите выполнять приведение, вы можете использовать шаблон команды, где каждый класс свойств GLSL получает указатель на объект Material и выполняет соответствующее действие.Каждой команде потребуется доступ к некоторым внутренним материалам.Код ниже иллюстрирует это.(обратите внимание, что все просто для простоты).

struct Material; // forward declaration
struct GlslPropertyBase {
    virtual ~GlslPropertyBase() {}
    virtual void Execute(Material* m) = 0;
};

struct Material {
    void SetBaseColor(Vec3 col) { /* Do something */ }
    void SetBaseTexture(GLuint uid) { /* Do something */ }

    Material(std::vector<GlslPropertyBase*> properties) {
        for (GlslPropertyBase* property : properties)
            property->Execute(this);
    }
};

struct GlSlBaseColor : GlslPropertyBase {
    Vec3 color;
    GlSlBaseColor(float r, float g, float b) : color(r, g, b) {}
    void Execute(Material* m) { m->SetBaseColor(color); }
};

struct GlSlBaseTexture : GlslPropertyBase {
    GLuint uid;
    GlSlBaseTexture(GLuint uid) : uid(uid) {}
    void Execute(Material* m) { m->SetBaseTexture(uid); }
};

int main() {
    std::vector<GlslPropertyBase*> properties;
    properties.push_back(new GlSlBaseColor(1, 2, 3));
    properties.push_back(new GlSlBaseTexture(1));

    Material PBR(properties);

    // delete heap objects...
}

Это простой способ (и реализация) для обработки разнородных свойств glsl, хранящихся в одном векторе, без приведения и, вероятно, что @francescoпредложил в конце свой ответ .

0 голосов
/ 21 января 2019

Как уже упоминалось в комментарии, без использования std::variant или эквивалентных boost классов невозможно достичь желаемого дизайна. Ключевым моментом является то, что виртуальный механизм позволяет решить во время компиляции, какую функцию-член вызывать, но не может определить во время выполнения тип переменной. Таким образом, что бы ни возвращал тип i->getValue(), вы не можете решить во время выполнения тип переменной, где хранить результат. То же самое происходит, если вы решите создать Derive<T>::getValue как void Derive<T>::getValue(T& x) { x = value; }: внутри цикла вы не сможете объявить локальную переменную x для передачи getValue.

В связи с этим см. Обсуждение Можно ли создавать объекты на основе type_info?

В качестве общего предложения: вам следует постараться как можно больше вставить в Derive задачи, которые вы хотите выполнить, и предоставить в Base только абстрактный интерфейс.

...