【问题标题】:Intel compiler failing to compile variadic lambda capture with multiple arguments英特尔编译器无法编译具有多个参数的可变参数 lambda 捕获
【发布时间】: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)并更改将参数传递给execconst&amp;)的方式,可以将错误报告为其他类型,即“std::move 的重载无法匹配”。此时,它也会在 icc16 上失败。这是稍微修改的代码:https://godbolt.org/g/qHrU6P

如果代码格式正确(我相信它是),除了用自定义函子替换 lambda(我不想这样做,因为我不想手动捕获具有适当引用的可变数量的参数)通过元组)有人在这里看到任何解决方法吗?

【问题讨论】:

  • 在 Godbolt 上的 ICC 16 上为我工作,但在 ICC 17 上它确实失败了。(你的问题有不同的说法。)
  • @CodyGray,如果您替换类型,它将失败,例如:godbolt.org/g/qHrU6P 在寻求简化问题时,我没有使用 icc16 检查最新版本。我将编辑问题以反映这一点。
  • 我认为将 std::forward&lt;ARGS&gt;(args)... 更改为 std::forward&lt;std::decay_t&lt;decltype(args)&gt;&gt;(args)... 可以解决问题
  • @W.F.不过,我怀疑它会做正确的事情。
  • @Sergey 是的,你是对的...:/

标签: c++ lambda icc


【解决方案1】:

我认为以下代码将满足您的解决方法要求:

#include <utility>
#include <iostream>
#include <tuple>

template<class CB, class... ARGS>
void call_lam(CB&& cb, ARGS&&... args) {
     auto lam = [](auto&&... args2){
         return [&args2...](auto&& callee) { 
                callee(std::forward<std::tuple_element_t<0, std::decay_t<decltype(args2)>>>(std::get<0>(args2))...);
         };}(std::forward_as_tuple(std::forward<ARGS>(args))...);
     lam(cb);
}

struct A {
    A() {
        std::cout << "A()" << std::endl;
    }
    A(const A&) {
        std::cout << "A(const A&)" << std::endl;
    }
    A(A&&) {
        std::cout << "A(A&&)" << std::endl;
    }
};

void exec(A &, A) {
}

int main() {
  A a;
  call_lam(exec, a, A());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多