std::bind 无法与 lua_call 兼容。

3

使用Lua 5.3.5和gcc 9.2.0的开发库时,我遇到了以下最小代码段的奇怪编译问题:

#include <functional>

extern "C" {
  #include "lua.h"
  #include "lualib.h"
}

int main()
{
  using namespace std::placeholders;

  auto lua_simple_call = std::bind(lua_call, _1, 0, 0);
}

gcc 报错: error: ‘lua_call’ was not declared in this scope。在不使用std::bind调用lua_call时,此问题不会出现,对于其他Lua C函数(如lua_newtable等)也不会出现。我想知道是什么原因导致这种情况以及如何避免。


lua_call 不是一个宏吗?它的定义是什么? - YSC
它确实是,但我认为没有问题,因为它只是扩展为对lua_callk的调用。 - Peter
为了理解为什么不可能,您需要多读一些有关预处理宏的工作方式的内容。从这里开始:https://dev59.com/GHM_5IYBdhLWcg3w-4rw 并深入探究。最终,您会找到一个解决方案。 - YSC
2
你可以将其包装成lambda表达式:[](lua_State* s){ lua_call(s,0,0); },或者传递指向Lua实际函数的指针,而不是宏定义:std::bind(lua_callk,_1,0,0,0,0) - rafix07
1个回答

7

正如 OP 所提到的,lua_call 是一个宏,它会扩展为 lua_callk,但这只是其中的一半真相。

lua_call 是一个函数宏:

github: lua.h

#define lua_call(L,n,r)     lua_callk(L, (n), (r), 0, NULL)

这就是差别所在。

因此,lua_call只有在使用正确数量的参数时才会扩展为lua_callk

我创建了一个MCVE来演示这一点:

#include <iostream>

#define lua_call(L, n, r) lua_callk(L, (n), (r))

void lua_callk(void *L, int n, int r)
{
  std::cout << "lua_callk(" << L << ", " << n << ", " << r << ")\n";
}

#define TEST(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  TEST(lua_call(nullptr, 2, 1));
  //TEST(std::cout << "&lua_call: " << &lua_call << '\n');
}

输出:

g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
lua_call(nullptr, 2, 1);
lua_callk(0, 2, 1)

coliru上的实时演示

相比之下:

#include <iostream>

#define lua_call(L, n, r) lua_callk(L, (n), (r))

void lua_callk(void *L, int n, int r)
{
  std::cout << "lua_callk(" << L << ", " << n << ", " << r << ")\n";
}

#define TEST(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  TEST(lua_call(nullptr, 2, 1));
  std::cout << "&lua_call: " << &lua_call << '\n');
}

输出:

main.cpp: In function 'int main()':
main.cpp:15:34: error: 'lua_call' was not declared in this scope
   15 |   std::cout << "&lua_call: " << &lua_call << '\n';
      |                                  ^~~~~~~~

在Coliru上查看实时演示

或者,为了更加明显:

//#include <iostream>

#define lua_call(L, n, r) lua_callk(L, (n), (r))

void lua_callk(void *L, int n, int r)
{
  std::cout << "lua_callk(" << L << ", " << n << ", " << r << ")\n";
}

#define TEST(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  TEST(lua_call(nullptr, 2, 1));
  std::cout << "&lua_call: " << &lua_call << '\n';
}

使用仅预处理器运行:

# 1 "main.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main.cpp"


void lua_callk(void *L, int n, int r)
{
  std::cout << "lua_callk(" << L << ", " << n << ", " << r << ")\n";
}


int main()
{
  std::cout << "lua_call(nullptr, 2, 1)" << ";\n"; lua_callk(nullptr, (2), (1));
  std::cout << "&lua_call: " << &lua_call << '\n';
}

点击此处查看在coliru上的演示


修复方法也很明显(如Rafix的评论中所提到的):

只需将lua_bind()包装到可寻址的函数或lambda中即可。


我现在感觉非常愚蠢,没有自己意识到这一点,但这是一个很好的解释! - Peter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接