此示例编译:
#include <cstddef>
template<class T>
int foo(const T* bar,size_t N)
{
return test(T{});
}
struct Type
{
};
inline constexpr int test(Type)
{return 0;}
int main()
{
Type vals[4];
return foo(vals,4);
}
对于其他类似的情况,我得到了
...在此处声明,稍后在翻译单元
结论:有时可以延迟声明符号,但并非总是如此。使这项工作的规则是什么?
非工作案例的编译器日志示例:
In file included from scene.hpp:9:0,
from scene.cpp:6:
angle/texture2d.hpp: In instantiation of ‘void Angle::Texture2D::dataSet(const T*, GLsizei, GLsizei) [with T = PageComposer::Surface::Pixel; GLsizei = int]’:
scene.cpp:26:68: required from here
angle/texture2d.hpp:138:68: error: ‘gl_format’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
glTextureSubImage2D(m_handle,0,0,0,width_in,height_in,gl_format(T{}),gl_type(T{})
^
scene.cpp:9:23: note: ‘constexpr auto gl_format(PageComposer::Surface::Pixel)’ declared here, later in the translation unit
inline constexpr auto gl_format(PageComposer::Surface::Pixel)
^
In file included from scene.hpp:9:0,
from scene.cpp:6:
angle/texture2d.hpp:138:81: error: ‘gl_type’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
glTextureSubImage2D(m_handle,0,0,0,width_in,height_in,gl_format(T{}),gl_type(T{})
^
scene.cpp:12:23: note: ‘constexpr auto gl_type(PageComposer::Surface::Pixel)’ declared here, later in the translation unit
inline constexpr auto gl_type(PageComposer::Surface::Pixel)
Angle :: Texture :: dataSet的定义如下所示:
template<class T>
void dataSet(const T* data,GLsizei width_in,GLsizei height_in)
{
if(m_width!=width_in || m_height!=height_in)
{realloc(width_in,height_in);} //Recreate the texture if resized.
glTextureSubImage2D(m_handle,0,0,0,width_in,height_in,gl_format(T{}),gl_type(T{})
,data);
if(m_levels>1)
{glGenerateTextureMipmap(m_handle);}
}
它不能单独使用此功能,因为这也可以编译并正常工作:
#include "vertexarray.hpp"
#include "program.hpp"
#include "init.hpp"
#include "contextguard.hpp"
#include "texture2d.hpp"
#include <geosimd/point.hpp>
#include <GLFW/glfw3.h>
struct GLFWContext
{
GLFWContext(const Angle::VersionRequest& version)
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, version.major);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, version.minor);
switch(version.profile)
{
case Angle::VersionRequest::Profile::CORE:
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
break;
case Angle::VersionRequest::Profile::COMPAT:
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
break;
case Angle::VersionRequest::Profile::ANY:
default:
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
break;
}
if(version.forward_compatible)
{glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);}
}
~GLFWContext()
{glfwTerminate();}
};
class Window
{
public:
typedef GLFWwindow* ContextHandle;
Window(const Window&)=delete;
Window& operator=(const Window&)=delete;
Window()
{m_handle=glfwCreateWindow(800,600,"",nullptr,nullptr);}
~Window()
{glfwDestroyWindow(m_handle);}
auto contextCapture() noexcept
{
auto ret=glfwGetCurrentContext();
glfwMakeContextCurrent(m_handle);
return ret;
}
static void contextRelease(GLFWwindow* window) noexcept
{glfwMakeContextCurrent(window);}
auto handle() noexcept
{return m_handle;}
bool shouldClose() const noexcept
{return glfwWindowShouldClose(m_handle);}
private:
GLFWwindow* m_handle;
};
static constexpr GeoSIMD::Point<float> verts[]=
{
GeoSIMD::Point<float>{0.5f, 0.5f, 0.0f}
,GeoSIMD::Point<float>{0.5f, -0.5f, 0.0f}
,GeoSIMD::Point<float>{-0.5f, -0.5f, 0.0f}
,GeoSIMD::Point<float>{-0.5f, 0.5f, 0.0f}
};
static constexpr uint16_t faces[]=
{
0,1,3
,1,2,3
};
template<class T>
static constexpr const GeoSIMD::vec4_t<T>* native_type(const GeoSIMD::Point<T>* point_ptr)
{return reinterpret_cast<const GeoSIMD::vec4_t<T>*>(point_ptr);}
struct MyShaderLayout
{
static constexpr Angle::VertexAttribute attributes[]=
{
{4,Angle::ConstantGet<float>::value}
};
};
constexpr Angle::VertexAttribute MyShaderLayout::attributes[];
struct RGB
{
uint8_t B;
uint8_t G;
uint8_t R;
uint8_t A;
};
static RGB g_texture[1200][1920];
static void textureFill()
{
for(size_t k=0;k<1200;++k)
{
for(size_t l=0;l<1920;++l)
{
g_texture[k][l].R=uint8_t(255*k/1200.0f);
g_texture[k][l].G=uint8_t(255*l/1920.0f);
g_texture[k][l].B=0;
g_texture[k][l].A=255;
}
}
}
inline constexpr auto gl_format(RGB)
{return GL_BGRA;}
inline constexpr auto gl_type(RGB)
{return GL_UNSIGNED_INT_8_8_8_8_REV;}
int main()
{
textureFill();
GLFWContext glfw(Angle::gl_version_requirements());
try
{
Window mainwin;
Angle::ContextGuard<Window> context(mainwin);
auto version=Angle::init();
printf("%s, %s, %s, %s\n"
,version.vendor
,version.renderer
,version.version
,version.glsl_version);
Angle::VertexBuffer<GeoSIMD::vec4_t<float>> vertbuff(4);
vertbuff.bufferData(native_type(verts),4);
Angle::VertexBuffer<uint16_t> facebuff(6);
facebuff.bufferData(faces,6);
Angle::Texture2D texture(1,Angle::TextureFormat::SRGB8_ALPHA8 ,1920,1200);
Angle::Program prgm(
R"EOF(#version 450 core
layout(location=0) in vec4 position;
out vec2 tex_coords;
void main()
{
gl_Position=position;
tex_coords=position.xy + vec2(0.5,0.5);
}
)EOF"_vert,R"EOF(#version 450 core
out vec4 color;
in vec2 tex_coords;
layout(location=0) uniform sampler2D texture_data;
void main()
{
color=texture(texture_data,tex_coords);
}
)EOF"_frag);
Angle::VertexArray<MyShaderLayout> vertex_array;
vertex_array.vertexBuffer<0>(vertbuff).enableVertexAttrib<0>()
.elementBuffer(facebuff);
texture.dataSet(&g_texture[0][0],1920,1200);
texture.bind(1);
glEnable(GL_FRAMEBUFFER_SRGB);
while(!mainwin.shouldClose())
{
glfwPollEvents();
vertex_array.bind();
prgm.bind();
glUniform1i(0,1);
Angle::drawElements(Angle::DrawMode::TRIANGLES,0,6);
glfwSwapBuffers(mainwin.handle());
}
}
catch(const Angle::Error& err)
{
fprintf(stderr,"Error: %s\n",err.message());
return -1;
}
return 0;
}
输出:
NVIDIA Corporation, GeForce GTX 1050 Ti/PCIe/SSE2, 4.5.0 NVIDIA 375.20, 4.50 NVIDIA
OpenGL: Buffer detailed info: Buffer object 1 (bound to NONE, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations.
OpenGL: Buffer detailed info: Buffer object 2 (bound to NONE, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations.