此代码:
void foo(int);
int main() {
const int i = 0;
auto l = [i](){foo(i);};
}
(godbolt)
使用
由clang编译时,将发出编译器错误 -std=c++17 -Werror -Wunused-lambda-capture
错误消息是error: lambda capture 'i' is not required to be captured for this use
。
错误是正确的:这里可以隐式捕获i
,而不必显式捕获。但是,a)警告的名称不正确,因为使用了i
,但是警告是针对未使用 lambda捕获的; b)我只是不希望这是一个错误。对于实际未使用的lambda捕获,我想出错,但对于可能被隐式捕获的已使用的显式捕获变量,我不希望出错。
是否有执行此操作的叮当声设置?还是我必须使用编译指示诊断推送/弹出来消除错误?
答案 0 :(得分:5)
我认为您在这里很不幸。如果我们检查实现此功能[Sema] Add warning for unused lambda captures的评论,就会发现有关如何使警告静音的讨论已得到广泛讨论。包括沉默未使用警告的规范clang方法,该方法强制转换为无效:
我认为不应在此处使用预期警告,因为您在lambda中具有(void)fname(如果在本地进行测试,则不会收到此警告)。
see it live确实可以使用,但是在这种情况下感觉很傻。
使用-Wno-unused-lambda-capture
,但这对您来说不是一个好选择:
我认为,如果将“ -Wno-unused-lambda-capture”添加到CXX /目录中此修补程序修改的所有测试的选项中,则该修补程序会更整洁。这样可以避免多余的(void)使用,并确保(void)使用不会干扰可能仅在捕获列表中使用的原始意图。
从捕获中删除变量,因为它没有被过分使用,但正如指出的那样,由于MSVC不执行此优化,因此暴露了实现上的分歧:
如果我从列表中删除kDelta,它将在没有任何警告的情况下进行编译 捕获数量:
#include <stdio.h> int main(void) { const int kDelta = 10000001; auto g = [](int i) { printf("%d\n", i % kDelta); }; g(2); }
但是随后Microsoft C ++编译器将引发错误:
error C3493: 'kDelta' cannot be implicitly captured because no default capture mode has been specified
我们可以看到这种情况live as well,并且确实从捕获中删除了i
确实可以解决clang和gcc,但不能解决MSVC。
适用于所有限制的另一种解决方案是显式捕获[i=i]
,但听起来这也不是理想的解决方案(see it live)。
如果我们可以在此处应用[[maybe_unused]],但不能在此应用,那就太好了。
答案 1 :(得分:0)
我没有一个好的解决方案,但是我们已经实施了一个解决方案。
void foo(int);
int main() {
const int i = 0;
auto l = [LAMBDA_CONSTANTS(&i)](){foo(i);};
}
LAMBDA_CONSTANTS是LambdaConstants.h中定义的宏,我们在需要时将其包括在内。
其内容是:
#ifndef LAMBDA_CONSTANTS_H
#define LAMBDA_CONSTANTS_H
/*
given a lambda that wants to capture two constants
const auto k1 = 1000;
const auto k2 = 2000;
int v = 0;
auto lambda = [&v, &k1, &k2]() {
v = k1 * k2;
}
Then unfortunately clang will correctly warn about unnecessary captures. And MSVC will fail to compile if you don't capture.
https://stackoverflow.com/questions/52416362/unused-lambda-capture-warning-when-capture-is-actually-used
An imperfect solution is to declare the lambda using the LAMBDA_CONSTANTS macro.
auto lambda = [&v
LAMBDA_CONSTANTS(&k1, &k2)
](){
v = k1 * k2;
}
This should work correctly. Most of the time.
NOTE: There is no comma after the final capture variable before the LAMBDA_CONSTANTS macro. The macro is variadic and will work with 1 or more captures.
*/
#ifndef LAMBDA_CONSTANTS
#if _MSC_VER
#define LAMBDA_CONSTANTS(...) ,__VA_ARGS__
#else
#define LAMBDA_CONSTANTS(...)
#endif
#endif
#endif // LAMBDA_CONSTANTS_H