【发布时间】:2017-05-05 23:31:16
【问题描述】:
这是我能想到的一个最小的例子:
#include <utility>
template<class CB, class... ARGS>
void call_lam(CB&& cb, ARGS&&... args) {
auto lam = [&args...](auto&& callee) {
callee(std::forward<ARGS>(args)...);
};
lam(cb);
}
void exec(unsigned, int);
void foo() {
unsigned x = 25;
int y = 0;
call_lam(exec, x, y);
}
上面的示例使用 CLang 和 gcc 编译,但使用 icc 17.0 编译失败(如 https://godbolt.org/g/tzMY6K 所示)。错误如下:
/usr/include/c++/5/bits/move.h(89):错误:静态断言失败 用“模板参数替换 _Tp 是左值引用类型”
static_assert(!std::is_lvalue_reference<_tp>::value, "模板 论据”
^ 在以下期间检测到:
“_Tp”的实例化 &&std::forward<_tp>(std::remove_reference<_tp>::type &&) [with _Tp=unsigned int &]" 在""的第 5 行
函数“lambda [](auto &&)->auto [with =void (&)(unsigned int, int)]”的实例化 在“”的第 7 行
实例化“void call_lam(CB &&, ARGS &&...) [with CB=void (&)(unsigned int, int), ARGS=]" at "" 编译中止(代码 2)的第 15 行
编译器退出,结果代码为 2
玩这个例子,我发现:
- 必须将不同类型作为
exec的参数。使用两个整数或单个参数时,错误消失 - 通过将类型替换为其他类型(例如,
std::string)并更改将参数传递给exec(const&)的方式,可以将错误报告为其他类型,即“std::move的重载无法匹配”。此时,它也会在 icc16 上失败。这是稍微修改的代码:https://godbolt.org/g/qHrU6P
如果代码格式正确(我相信它是),除了用自定义函子替换 lambda(我不想这样做,因为我不想手动捕获具有适当引用的可变数量的参数)通过元组)有人在这里看到任何解决方法吗?
【问题讨论】:
-
在 Godbolt 上的 ICC 16 上为我工作,但在 ICC 17 上它确实失败了。(你的问题有不同的说法。)
-
@CodyGray,如果您替换类型,它将失败,例如:godbolt.org/g/qHrU6P 在寻求简化问题时,我没有使用 icc16 检查最新版本。我将编辑问题以反映这一点。
-
我认为将
std::forward<ARGS>(args)...更改为std::forward<std::decay_t<decltype(args)>>(args)...可以解决问题 -
@W.F.不过,我怀疑它会做正确的事情。
-
@Sergey 是的,你是对的...:/