英特尔编译器无法使用多个参数编译可变参数lambda捕获

时间:2016-12-20 17:01:33

标签: c++ lambda icc

这是我能够提出的最小例子:

#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&lt; _Tp&gt; :: value,“template   变量“

     

^期间检测到:

     

实例化“_Tp   &amp;&amp; std :: forward&lt; _Tp&gt;(std :: remove_reference&lt; _Tp&gt; :: type&amp;&amp;)[with   _Tp = unsigned int&amp;]“在”

的第5行      

实例化函数“lambda [](auto&amp;&amp;) - &gt; auto [with = void(&amp;)(unsigned int,int)]”   在“”

的第7行      实例化“void call_lam”(CB&amp;&amp;,ARGS   &amp;&amp; ...)[与CB = void(&amp;)(unsigned int,int),ARGS =]“在第15行”编译中止(代码2)

     

编译器退出,结果代码为2

玩这个例子,我发现:

  • 必须将不同类型作为exec的参数。当使用两个整数或一个参数时,错误消失
  • 通过使用其他内容替换类型(例如,std::string)并将参数传递方式更改为execconst&),可以将错误报告为其他内容,并说“std::move的重载无法匹配”。此时,它也会在icc16上失败。这是稍加修改的代码:https://godbolt.org/g/qHrU6P

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

1 个答案:

答案 0 :(得分:0)

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

#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());
}