std::bind 不能与 lua_call 互操作

Pet*_*ter 3 c++ lua c++11

使用 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);
}
Run Code Online (Sandbox Code Playgroud)

gcc 抱怨:error: ‘lua_call’ was not declared in this scope. 尝试在lua_call不使用的情况下简单调用时不会发生此问题,std::bind并且其他 Lua C 函数(如lua_newtable等)似乎也不会发生此问题。我想知道是什么导致了这种情况以及如何规避它。

Sch*_*eff 7

正如 OP 所提到的,lua_call是一个扩展为的宏,lua_callk但这只是事实的一半。

lua_call是一个函数宏:

github: lua.h

#define lua_call(L,n,r)     lua_callk(L, (n), (r), 0, NULL)
Run Code Online (Sandbox Code Playgroud)

这就是区别。

因此,仅当与正确数量的参数一起使用时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');
}
Run Code Online (Sandbox Code Playgroud)

输出:

#define lua_call(L,n,r)     lua_callk(L, (n), (r), 0, NULL)
Run Code Online (Sandbox Code Playgroud)

在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');
}
Run Code Online (Sandbox Code Playgroud)

输出:

#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');
}
Run Code Online (Sandbox Code Playgroud)

在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';
}
Run Code Online (Sandbox Code Playgroud)

仅使用预处理器运行:

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

在coliru上进行现场演示


修复也很明显(如Rafix 的评论中已经提到的):

只需包装lua_bind()成可寻址的东西:函数或 lambda。