如何在没有代码重复的情况下为模板设置多个指定方法?

时间:2019-01-24 15:08:52

标签: c++ templates polymorphism

我正在用cpp做一个项目,并且在设计类时遇到一个问题。 我的类名为“ Uniform”,它的模板类型为T,它有一个构造函数,一个析构函数和一个名为“ Bind”的函数,该函数对Shader类型的对象进行引用并返回void。它也很重要,但我认为这并不重要。我想根据T调用一个不同的绑定方法,专门。

我已经尝试为etch Uniform定义一个新的专用模板化类(在本例中为3),但是它对结果不满意,因为这会创建代码重复。我还尝试根据绑定模板链接绑定,这给了我一个链接错误,如下例:

//This is giving link errors
#define I_UNIFORM_CONSTRUCT(x) Uniform(std::string name, x * data , unsigned int count)\
:  IUniform(name,  count),data(data) {}

class IUniform {
public:
    std::string name;

    unsigned int count;
    IUniform(std::string name , unsigned int count ) {
        this->name = name;
        this->count = count;}
    virtual void Bind(Shader & shader) {};
};

template <class T> class Uniform : public IUniform{
public:
    T * data;
    I_UNIFORM_CONSTRUCT(T)

    void Bind(Shader & shader);
    ~Uniform()
    {
        delete[] this->data,sizeof(T)*count;
    }
};

template <class T> void Uniform<T>::Bind(Shader & shader) {
    std::cout << "Error unsupported uniform" << std::endl;
}
template <> void Uniform<float>::Bind(Shader & shader) {
    if (this->count == 4)shader.SetUniform4f(this->name, *(glm::vec4*)this->data);
    else if (this->count == 1)shader.SetUniform1f(this->name, *(float*)this->data);
}
template <> void Uniform<glm::mat4>::Bind(Shader & shader) {
    if (this->count == 1)shader.SetUniformMat4f(this->name, *(glm::mat4*)this->data);
}

template <> void Uniform<int>::Bind(Shader & shader) {
    if (this->count == 1)shader.SetUniform1i(this->name, *(int*)this->data);
}

还有我将要删除的第二个工作示例:


#define I_UNIFORM_CONSTRUCT(x) Uniform(std::string name, x * data , unsigned int count)\
:  IUniform(name,  count),data(data) {}

class IUniform {
public:
    std::string name;

    unsigned int count;
    IUniform(std::string name , unsigned int count ) {
        this->name = name;
        this->count = count;}
    virtual void Bind(Shader & shader) {};
};

template <class T> class Uniform : public IUniform{
public:
    T * data;
    I_UNIFORM_CONSTRUCT(T)

    void Bind(Shader & shader)override {
        std::cout << "Error unsupported uniform" << std::endl;
    }
    ~Uniform()
    {
        delete[] this->data,sizeof(T)*count;
    }
};

template <> class Uniform<float> : public IUniform {
public:
    float * data;
    I_UNIFORM_CONSTRUCT(float)

    void Bind(Shader & shader)override {
        if (this->count == 4)shader.SetUniform4f(this->name, *(glm::vec4*)this->data);
        else if (this->count == 1)shader.SetUniform1f(this->name, *(float*)this->data);}
    ~Uniform()
    {
        delete[] this->data, sizeof(float)*count;
    }
};

template <> class Uniform<glm::mat4> : public IUniform {
public:
    glm::mat4 * data;
    I_UNIFORM_CONSTRUCT(glm::mat4)
    void Bind(Shader & shader)override {
        if (this->count == 1)shader.SetUniformMat4f(this->name, *(glm::mat4*)this->data);}
    ~Uniform()
    {
        delete[] this->data, sizeof(glm::mat4)*count;
    }
};

template <> class Uniform<int> : public IUniform {
public:
    int * data;
    I_UNIFORM_CONSTRUCT(int)
    void Bind(Shader & shader)override {
        if (this->count == 1)shader.SetUniform1i(this->name, *(int*)this->data);}
    ~Uniform()
    {
        delete[] this->data, sizeof(int)*count;
    }
};//Too ugly 

我希望第一个示例根据T的类型调用专门的Bind,但目前它不链接。说我无法多次定义绑定... 任何人都可以帮助我解决第一个示例或使第二个示例更具可读性吗?

1 个答案:

答案 0 :(得分:0)

为阐明我们在评论中的解释,

提供具有相同名称的重载,这些重载可以调用Shader方法:

void SetUniform(Shader& shader, const std::string& name, glm::vec4& data)
{
    shader.SetUniform4f(name, data);
}
void SetUniform(Shader& shader, const std::string& name, float& data)
{
    shader.SetUniform1f(name, data);
}
void SetUniform(Shader& shader, const std::string& name, glm::mat4& data)
{
    shader.SetUniformMat4f(name, data);
}
void SetUniform(Shader& shader, const std::string& name, int& data)
{
    shader.SetUniform1i(name, data);
}

然后

class IUniform
{
public:
    std::string name;

    IUniform(const std::string& name) : name(name) {}
    virtual ~IUniform() = default;
    virtual void Bind(Shader&) = 0;
};

template <class T> class Uniform : public IUniform{
public:
    T data;
    Uniform(const std::string& name, const T& data) : IUniform(name), data(data) {}

    void Bind(Shader& shader) override { SetUniform(shader, name, data);}
};

最后,您可以使用Uniform<glm::mat4>Uniform<glm::vec4>Uniform<float>Uniform<int>