【问题标题】:std::bind not interoperable with lua_callstd::bind 不能与 lua_call 互操作
【发布时间】:2020-06-23 10:20:36
【问题描述】:

使用 Lua 5.3.5 和 gcc 9.2.0 的开发库我遇到了以下最小 sn-p 的奇怪编译问题:

#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 不是宏吗?它的定义是什么?
  • 是的,但我没有看到问题,因为它只是扩展为对 lua_callk 的调用。
  • 为了理解为什么这是不可能的,您需要阅读更多关于预处理宏的工作方式的信息。从这里开始:stackoverflow.com/questions/1137575/… 并深入了解。最终,您会找到解决方案。
  • 您可以将其包装成 lambda:[](lua_State* s){ lua_call(s,0,0); } 或将指针传递给 Lua 的真正函数,而不是宏:std::bind(lua_callk,_1,0,0,0,0)

标签: c++ c++11 lua


【解决方案1】:

正如 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)

Live Demo on 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';
      |                                  ^~~~~~~~

Live Demo on 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';
}

Live Demo on coliru


修复也很明显(正如Rafix' comment 中已经提到的):

只需将 lua_bind() 包装成可寻址的对象:函数或 lambda。

【讨论】:

  • 我现在因为自己没有意识到这一点而感到非常愚蠢,但无论如何这是一个很好的解释!
猜你喜欢
  • 1970-01-01
  • 2018-03-13
  • 2014-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多