我有一个在头文件中共享的变量。它是用 lambda 初始化的。我希望从另一个翻译单元调用一个函数,并以此 lambda 变量作为参数。
使用 gcc,我收到错误:
used but never defined [-fpermissive].
这是一个简化的示例:
// in shared header file
//
const auto make_lambda() { return [](){ }; }
inline const auto lambda = make_lambda();
// in cpp file
//
void func(const decltype(lambda)&);
int main() {
func(lambda);
}
我的理解是 lambda 类型应该在翻译单元之间共享。
当我将 lambda 变量更改为以下内容时,问题就消失了:
inline const auto lambda = [](){ }; // <-- this does work
最佳答案
Clang 提供了出色的诊断,可以解释 make_lambda
的问题嗯:
<source>:8:6: error: function 'func' is used but not defined in this translation unit,
and cannot be defined in any other translation unit because its type
does not have linkage
void func(const decltype(lambda)&);
^
“无链接”意味着:
When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.
我们的 lambda 没有链接的原因是它定义的闭包类型是在 make_lambda
的内部定义的。 。结果是:
Names not covered by these rules have no linkage. Moreover, except as noted, a name declared at block scope has no linkage.
您尝试使用的类型是 make_lambda::__lambda
本质上,这不能跨不同的 TU 使用。
共享 lambda 表达式的 ODR 问题
inline const auto lambda = [](){ };
...使编译器错误消失,但这会使您的程序格式错误,无需诊断。我们必须尊重单一定义规则,但我们违反了以下规定:
In each such definition, except within the default arguments and default template arguments of
D
, corresponding lambda-expressions shall have the same closure type (see below).
每个 TU 都有自己独特的闭合类型,但是 lambda
到处都必须有相同的定义。 这是 ODR 违规行为。
如果你真的坚持这样做,安全的方法是将其放入类类型中:
struct dummy {
using lambda_type = [] {};
};
dummy::lambda_type
将具有链接并且不违反 ODR。
另请参阅:[basic.def.odr]/16
结论
只是不要在不同的 TU 之间共享 lambda。即使你让它工作,解决方案也不是很好。相反,请考虑:
- 编写一个接受任何可调用内容的函数模板
- 接受函数指针
- 接受
std::function
- 创建一个常规类,而不是 lambda,它具有重载的调用运算符
所有这些选项都比尝试在 TU 之间共享 lambda 表达式(在函数之外)要好得多。
关于c++ - 翻译单元之间共享的 Lambda 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76582942/