1

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?

H4nzzU
  • 13
  • 3
  • You must have wrote it in a header that you `#included` multiple times. Begin your specialization with `template<> inline void ...` to allow multiple definitions and make sure your header uses include guards or `#pragma once`. – Yakov Galka Mar 25 '21 at 22:03
  • I was already using `#pragma once` but this `inline` keyword made everything work. Last question, in terms of performance and code clarity - is overloading (your second solution) more optimal ? – H4nzzU Mar 26 '21 at 15:48
  • 1
    In terms of performance they will be the same. In terms of code clarity -- I think that you're better off with not writing that class at all. It looks like a lot of code for what will be, in the end, just a couple of `glVertexAttribPointer` calls. – Yakov Galka Mar 26 '21 at 16:23
  • Thanks a lot for your reply! I'll consider this. – H4nzzU Mar 26 '21 at 17:48

1 Answers1

1

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 });
    }
    //...
};
Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • Thanks for fast reply! I've tried your first solution but i got error "multiple definition of " from it. While using overloading, how exactly does it work? I am pretty new to c++ and I am wondering what (T*)0 and GLfloat* mean ? – H4nzzU Mar 25 '21 at 12:50
  • 1
    @H4nzzU: you must have done something wrong then in the first. As for the second: `GLfloat*` is a pointer to `GLfloat`. Whereas `(T*)0` is null pointer of type `T`. – Yakov Galka Mar 25 '21 at 15:58
  • Hi, could you please take a look at my specified question? I've edited it. – H4nzzU Mar 25 '21 at 21:52