1

This example compiles:

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

For other similar situations I get

... declared here, later in the translation unit

Conclusion: Sometimes it is possible to declare the symbol late, but not always. What are the rules for making this work?

Example compiler log for non-working case:

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) 

The definition of Angle::Texture::dataSet looks like this:

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

It cannot be this function alone, because this also compiles and works correctly:

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

Output:

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

user877329
  • 6,717
  • 8
  • 46
  • 88
  • 1
    Another example that does NOT work (one of your "other similar situations") and emits the messaging similar to what you described, would probably amplify what may be going on. Consider adding such a case. – WhozCraig Feb 21 '17 at 11:25
  • @WhozCraig It always happens when things are more involved – user877329 Feb 21 '17 at 11:28
  • 1
    They have to be declared before use. The compiler is just helpful and tells you that it has found the functions, but too late. In your first example, you call a function `test` that depends on the template type, so the lookup has to be deferred until the template type is known. In the second example `glTextureSubImage2D` is not a template so the lookup is done immediately. – Bo Persson Feb 21 '17 at 12:06
  • But dataSet is a template, and everything works in the test file for angle. – user877329 Feb 21 '17 at 12:10
  • Vote to close, It is a duplicate, and the problem is that Pixel is not defined in global namespace. – user877329 Feb 21 '17 at 12:31

0 Answers0