【问题标题】:OpenGL -- Explicit specialization in non-namespace scope -- Function templates [duplicate]OpenGL——非命名空间范围内的显式特化——函数模板[重复]
【发布时间】:2021-03-25 00:01:30
【问题描述】:

最近我在 YouTube 上学习 OpenGL 基础知识,当我使用 VS C++ 编译器时,一切都像一个魅力,但自从我搬到 Clang 后,我从下面的代码中收到错误“非命名空间范围内的显式专业化”:

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

*这是一段不完整的类定义,但我想让这段代码更清晰。

基本上,我想要的只是创建几个函数,每个类型都有一个(我是模板的新手 :D)。 我将 Clion 与 MinGW64 Clang 和 C++20 一起使用。

我知道 VS C++ 编译器添加了一个非标准特性来支持这一点, 而 Clang 只使用标准方法。

谁能告诉我解决方法?

编辑 1:

尝试从 Yakov Galka 的回答中实施第一个解决方案。 我猜这两个 [[nodiscard]] 行或 m_Stride 变量可能会搞砸。我收到错误“多重定义”。

(这次是完整的代码)我应该从一开始就这样发布。

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

在这种情况下,正确的实现是什么?

【问题讨论】:

  • 你必须在你#included多次的标题中写过它。以template&lt;&gt; inline void ... 开始您的专业化,以允许多个定义并确保您的标头使用包含保护或#pragma once
  • 我已经在使用 #pragma once 但这个 inline 关键字让一切正常。最后一个问题,就性能和代码清晰度而言 - 重载(您的第二个解决方案)是否更优化?
  • 在性能方面它们将是相同的。在代码清晰度方面——我认为你最好不要写那个类。看起来有很多代码,最终只有几个 glVertexAttribPointer 调用。
  • 非常感谢您的回复!我会考虑的。

标签: c++ opengl clang explicit-specialization


【解决方案1】:

错误表示它希望您在命名空间范围内提供专业化。这样编译:

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

或者,您可以使用常规重载来避免专门化:

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

【讨论】:

  • 感谢您的快速回复!我已经尝试了您的第一个解决方案,但我收到了错误“ 的多重定义”。在使用重载时,它究竟是如何工作的?我对 c++ 很陌生,我想知道 (T*)0 和 GLfloat* 是什么意思?
  • @H4nzzU:你一定是一开始就做错了什么。至于第二个:GLfloat* 是指向GLfloat 的指针。而(T*)0T 类型的空指针。
  • 嗨,你能看看我指定的问题吗?我已经编辑过了。
猜你喜欢
  • 1970-01-01
  • 2011-08-12
  • 2011-03-04
  • 1970-01-01
  • 2018-09-17
  • 2019-10-03
相关资源
最近更新 更多