ImTheSquid
ImTheSquid

Reputation: 405

Using a member function pointer with a template argument

I am currently trying to make a universal function for setting various values inside of another object's class (specifically the Shader class). Here are some examples of what I am trying to set:

void setBool(const std::string& name, bool value) const {
    glUniform1i(glGetUniformLocation(shaderProgram, name.c_str()), (int)value);
}

void setInt(const std::string& name, int value) const {
    glUniform1i(glGetUniformLocation(shaderProgram, name.c_str()), value);
}

void setFloat(const std::string& name, float value) const {
    glUniform1f(glGetUniformLocation(shaderProgram, name.c_str()), value);
}

void setVec2(const std::string& name, const glm::vec2& value) const {
    glUniform2fv(glGetUniformLocation(shaderProgram, name.c_str()), 1, &value[0]);
}

void setVec3(const std::string& name, const glm::vec3& value) const {
    glUniform3fv(glGetUniformLocation(shaderProgram, name.c_str()), 1, &value[0]);
}

void setVec4(const std::string& name, const glm::vec4& value) const {
    glUniform4fv(glGetUniformLocation(shaderProgram, name.c_str()), 1, &value[0]);
}

void setMat2(const std::string& name, const glm::mat2& mat) const {
    glUniformMatrix2fv(glGetUniformLocation(shaderProgram, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

void setMat3(const std::string& name, const glm::mat3& mat) const {
    glUniformMatrix3fv(glGetUniformLocation(shaderProgram, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

void setMat4(const std::string& name, const glm::mat4& mat) const {
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

Here is the function that I am trying to use:

template <class T>
void setUniforms(void(Shader::*fp)(const std::string&, const T&), const std::string& name, T value) {
    for (auto iter = shaderMap.cbegin(); iter != shaderMap.cend(); ++iter) {
        (iter->second->*fp)(name, T(value));
    }
};

Here is my function call:

manager.setUniforms<const glm::mat4&>(&Shader::setMat4, "view", Camera::getLookMat());

Where Camera::getLookMat() returns a glm::mat4. However, when I try to compile, I get this error:

Error   C2664   'void ShaderManager::setUniforms<const glm::mat4&>(void (__thiscall Shader::* )(const std::string &,T),const std::string &,T)': cannot convert argument 1 from 'void (__thiscall Shader::* )(const std::string &,const glm::mat4 &) const' to 'void (__thiscall Shader::* )(const std::string &,T)' C2MEngine   D:\Programming\C++\C2MEngine\src\testing\Main.cpp   85  

Is there any way that I could reconfigure the function to work with the listed functions? All functions in this post are member functions, with the second code block being part of a separate class than the first block. I'm unsure if I'm having problems with either the member function pointer or the template.

Upvotes: 0

Views: 163

Answers (2)

aschepler
aschepler

Reputation: 72281

Reformatting that error message:

Error   C2664   
'void ShaderManager::setUniforms<const glm::mat4&>(
    void (__thiscall Shader::* )(const std::string &,T),
    const std::string &,T)':
cannot convert argument 1 from
    'void (__thiscall Shader::* )(const std::string &,const glm::mat4 &) const'
to
    'void (__thiscall Shader::* )(const std::string &,T)'
C2MEngine   D:\Programming\C++\C2MEngine\src\testing\Main.cpp   85  

One difference in the types is of course the general template parameter T in place of a specific type const glm::mat4&. You specified the template argument as const glm::mat4&, so that should be fine. The other difference is what's causing an issue: note the const at the end of the first function pointer type.

A const on a member function type is part of the function type, and there are no standard conversions for pointers to those types, to make sure const-correctness is not accidentally bypassed.

So add the final const to the function pointer type:

template <class T>
void setUniforms(void(Shader::*fp)(const std::string&, const T&) const,
                 const std::string& name,
                 T value);

(Modified from the declaration in your question, although the error message implies the function pointer's value parameter has type T, not const T&.)

If you wanted, you could also use an alias template to make that less verbose, and the name of the fp function parameter more obvious:

template <class T> using ShaderSetFuncPtr =
    void (Shader::*)(const std::string&, const T&); // or ,T ?
template <class T>
void setUniforms(ShaderSetFuncPtr<T> fp, const std::string& name, T value);

Upvotes: 2

r3mus n0x
r3mus n0x

Reputation: 6144

You are missing a const qualifier in your member-function pointer:

template <class T>
void setUniforms(void(Shader::*fp)(const std::string&, const T&) const, const std::string& name, T value)
//                                              added const here ~~~~^

While all of your setters are (surprisingly!) const-qualified.

Upvotes: 2

Related Questions