传递静态成员函数作为参数时的未定义引用

时间:2013-10-31 13:51:10

标签: c++ glfw

我正在尝试将我的glfw错误和关键回调设置为类Game中的函数。这样做时,我得到了对回调函数的未定义引用。

以下是该课程的相关部分:

namespace TGE
{
    class Game
    {
        public:
            void init()
            {
                glfwSetErrorCallback(error_callback)

                if(!glfwInit())
                    exit(EXIT_FAILURE);

                window = glfwCreateWindow(800, 600, "Test", NULL, NULL);

                if(!window)
                {
                    glfwTerminate();
                    exit(EXIT_FAILURE);
                }

                glfwMakeContextCurrent(window);
                glfwSetKeyCallback(window, key_callback);

                start();
            }

            void start()
            {
                // Main loop stuff
            }

            static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
            {
                if(action == GLFW_PRESS)
                {
                    switch(key)
                    {
                        case GLFW_KEY_ESCAPE:
                            glfwSetWindowShouldCLose(window, GL_TRUE);
                            break;
                    }
                }
            }

            static void error_callback(int error, const char* description)
            {
                fputs(description, stderr);
            }

        protected:
            GLFWwindow* window;
    }
}

当我尝试编译时,我得到了

In function `TGE::Game::init()`:
undefined reference to `TGE::Game::error_callback(int, char const*)`
undefined reference to `TGE::Game::key_callback(GLFWwindow*, int, int, int, int)`

我有一种感觉,可能是因为名称空间,但我不确定如何解决这个问题。

编辑:将所有内容移出命名空间会导致同样的错误。

2 个答案:

答案 0 :(得分:-1)

我认为是因为您对error_callback(...)key_callback(...)的定义是在init()函数之后,两者都使用了。

修改 忽略这一点,这不是原因,因为它是一个链接器错误(见下面的评论)

答案 1 :(得分:-1)

我怀疑这里发生的是你在类声明中定义了静态成员函数,这使得它们隐式inline。由于某些编译器错误(或者甚至可能是标准指定的行为?),编译器没有实例化这些实际上具有地址和全​​局符号的函数的非内联版本。

这是否是正确的行为,无论如何仅用作通过指针回调的内联函数是无稽之谈。那么为什么它不起作用是没有实际意义的。通过指针进行的函数调用不会内联。

您应该只在类声明中声明这些函数,然后在某处实现它们。

// inside the class decl:
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);

// inside some implementation file

#include "the_above_header.h"

// ...
void TGE::Game::key_callback(GLFWwindow*, int, int, int, int)
{
   // ...
}

确保编译并链接此文件。

然而,这个令状,以下测试程序为我编译和链接g ++ 4.6.3。

#include <stdlib.h>
#include <stdio.h>

// Wrapping the class in a namespace makes no difference, by the way.
class test {
  int x[42];
public:
  test()
  {
    qsort(x, 42, sizeof x[0], compare);
  }
  static inline int compare(const void *, const void *)
  {
    return 0;
  }
};

int main(void)
{
  test t;
  return 0; 
}