何时可以在以后声明从模板访问的符号

时间:2017-02-21 11:20:50

标签: c++ templates translation-unit

此示例编译:

#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.

Working example

0 个答案:

没有答案