c++openglclangexplicit-specialization

OpenGL -- Explicit specialization in non-namespace scope -- Function templates


Recently I was learning OpenGL basics from YouTube and while I was working with VS C++ compiler, everything worked like a charm, but since I moved to Clang I get error "explicit specialization in non-namespace scope" from the code below:

class VertexBufferLayout{
private:
    std::vector<VertexBufferElement> m_Elements;
public:
    VertexBufferLayout(){}

    template< typename T >
    void Push(GLuint count){}

    template<>
    void Push<GLfloat>(GLuint count){
        m_Elements.push_back({ GL_FLOAT, count, GL_FALSE });
        //Rest of code
    }
};

*It's an incomplete piece of class definition but I wanted to make this code more clear.

Basically, all I want is to create few functions, one for every type (and I am a newbie to templates :D). I'm using Clion with MinGW64 Clang and C++20.

I know that VS C++ compiler added a not-standard feature to support this, and Clang uses only standard methods.

Can anyone please tell me the workaround?

EDIT 1:

Attempt to implement the first solution from Yakov Galka's answer. I guess these two [[nodiscard]] lines or m_Stride variable might mess something up. I get the error "multiple definition of ".

(complete code this time) I should've posted it that way from the beginning.

class VertexBufferLayout{
    std::vector<VertexBufferElement> m_Elements;
    GLuint m_Stride;
public:
    VertexBufferLayout(): m_Stride(0) {}

    [[nodiscard]] std::vector<VertexBufferElement> GetElements() const& { return m_Elements; };
    [[nodiscard]] inline GLuint GetStride() const { return m_Stride; }

    template< typename T >
    void Push(GLuint count){}
};

template<>
void VertexBufferLayout::Push<GLfloat>(GLuint count){
    m_Elements.push_back({ GL_FLOAT, count, GL_FALSE });
    m_Stride += count * VertexBufferElement::GetSizeOfType(GL_FLOAT);
}

What is the right implementation in this case?


Solution

  • The error says that it wants you to provide the specialization at a namespace scope. This compiles:

    class VertexBufferLayout{
        std::vector<VertexBufferElement> m_Elements;
    public:
        VertexBufferLayout(){}
    
        template< typename T >
        void Push(GLuint count){}
    };
    
    template<>
    void VertexBufferLayout::Push<GLfloat>(GLuint count){
        m_Elements.push_back({ GL_FLOAT, count, GL_FALSE });
    }
    //...
    

    Alternatively, you can use regular overloading to avoid specialization:

    class VertexBufferLayout{
        std::vector<VertexBufferElement> m_Elements;
    public:
        VertexBufferLayout(){}
    
        template< typename T >
        void Push(GLuint count){ Push_(count, (T*)0); }
    
        void Push_(GLuint count, GLfloat*){
            m_Elements.push_back({ GL_FLOAT, count, GL_FALSE });
        }
        //...
    };