Использование указателя на функцию-член с аргументом шаблона - PullRequest
0 голосов
/ 24 марта 2020

В настоящее время я пытаюсь создать универсальную функцию для установки различных значений внутри класса другого объекта (в частности, класса Shader). Вот несколько примеров того, что я пытаюсь установить:

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]);
}

Вот функция, которую я пытаюсь использовать:

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));
    }
};

Вот мой вызов функции:

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

Где Camera::getLookMat() возвращает glm::mat4. Тем не менее, когда я пытаюсь скомпилировать, я получаю эту ошибку:

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  

Можно ли как-то перенастроить функцию для работы с перечисленными функциями? Все функции в этом посте являются функциями-членами, причем второй блок кода является частью отдельного класса, чем первый блок. Я не уверен, что у меня проблемы с указателем на функцию-член или с шаблоном.

Ответы [ 2 ]

2 голосов
/ 24 марта 2020

Переформатирование этого сообщения об ошибке:

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  

Разница в типах, конечно, заключается в общем параметре шаблона T вместо определенного c типа const glm::mat4&. Вы указали аргумент шаблона как const glm::mat4&, так что все должно быть в порядке. Другое отличие состоит в том, что вызывает проблему: обратите внимание на const в конце первого типа указателя на функцию.

A const для типа функции-члена является частью типа функции, и нет стандартные преобразования для указателей на эти типы, чтобы убедиться, что правильность констант не была случайно обойдена.

Так что добавьте окончательный const к типу указателя на функцию:

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

(Изменено из объявление в вашем вопросе, хотя сообщение об ошибке подразумевает, что параметр значения указателя функции имеет тип T, а не const T&.)

Если вы хотите, вы также можете использовать шаблон псевдонимов, чтобы сделать его менее подробным и имя параметра функции fp более очевидно:

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);
2 голосов
/ 24 марта 2020

В вашем указателе функции-члена отсутствует квалификатор const:

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

В то время как все ваши сеттеры (на удивление!) const -квалифицированы.

...