Yes it is. I use template to solve the problem. Here is my solution.
Since the template code in C++ is overly verbose and quite similar, I'm only pasting snippets as examples.
These template codes primarily utilize variable-length template parameters and constexpr if. When calling these wrappers, the C++ compiler can automatically deduce the template type based on your parameters, without you having to explicitly declare any template type parameters.
Of course, if you're dealing with bulk transfer of uniform data to OpenGL, the UBO (Uniform Buffer Object) solution mentioned in the previous answer is definitely better. My scheme is simply an experimental encapsulation.
template <typename T, typename... Args> constexpr bool all_same_type_v = (std::is_same_v<T, Args> && ...); //wrapper for glUniform number type template<typename... Args> void glUniform(GLint location, Args... values) { constexpr GLuint numOfArgs = sizeof...(values); static_assert(numOfArgs < 5, "Size of arguments must less than 5"); if constexpr (numOfArgs == 1) { if constexpr (all_same_type_v<float, Args...>) { glUniform1f(location, std::forward<Args>(values)...); } else if constexpr (all_same_type_v<GLint, Args...>) { glUniform1i(location, std::forward<Args>(values)...); } //..... //Wrapper for glUniformVec template<GLuint UVarLength, typename T> void glUniformVec(GLint location, GLsizei uniformVarCount, T* data) { assert(uniformVarCount < 5); if constexpr (UVarLength == 1) { if constexpr (std::is_same_v<T, float>) { glUniform1fv(location, uniformVarCount, data); } else if constexpr (std::is_same_v<T, GLint>) { glUniform1iv(location, uniformVarCount, data); } else if constexpr (std::is_same_v<T, GLuint>) { glUniform1uiv(location, uniformVarCount, data); } } else if constexpr (UVarLength == 2) //..... //wrapper for uniform matirx, value is a glm matrix type template<GLuint Cols, GLuint Rows,glm::qualifier q> void glUniformMatrix(GLint location, const glm::mat<Cols, Rows,glm::f32, q>& value) { if constexpr (Cols == 2) { if constexpr (Rows == 2) { glCall(glUniformMatrix2fv,location, 1, GL_FALSE, glm::value_ptr(value)); } else if constexpr (Rows == 3) { glCall(glUniformMatrix2x3fv,location, 1, GL_FALSE, glm::value_ptr(value)); } else if constexpr (Rows == 4) { glCall(glUniformMatrix2x4fv,location, 1, GL_FALSE, glm::value_ptr(value)); } else { static_assert(false, "Unsupport matrix type"); } } else if constexpr (Cols == 3) { if constexpr (Rows == 2) { glCall(glUniformMatrix3x2fv,location, 1, GL_FALSE, glm::value_ptr(value)); } //......
However, the problem what annoyed me at present is sometimes I mismatch the type in shaders and glUniform family methods. I'm finding some solution to check this error.