【问题标题】:What is this compiler error when using a lambda as a template parameter?使用 lambda 作为模板参数时,这个编译器错误是什么?
【发布时间】:2013-05-15 17:55:11
【问题描述】:

编辑:

这已在 Microsoft Connect (link) 上报告为 VS2012 C++ 编译器错误。

十一月2014 年 1 月 11 日:Microsoft 已回复称此错误的修复程序应该会出现在 Visual C++ 的下一个主要版本中。


我一直在为一个我不理解的 VS2012 编译器错误消息而苦苦挣扎,所以我将问题缩减到最低限度。

我正在使用 VS2012 构建以下 main.cpp

#include <utility>

template <typename T>
struct A
{
    T x;
    A(A&& other) : x(std::move(other.x)) { }
    A(T&& x) : x(std::move(x)) { }
};

template <typename T>
A<T> build(T&& x)
{
    return A<T>(std::move(x));
}

int main(int argc, char* argv[])
{
    auto f = []()
    {
        return build([](){}); //error here
    };
    return 0;
}

重点是我正在尝试使用 lambda 作为 build 函数的模板类型 T。我得到的错误信息是:

1>  main.cpp
1>C:\test\main.cpp(21): error C2664: 'A<T>::A(A<T> &&)' : cannot convert parameter 1 from 'A<T>' to 'A<T> &&'
1>          with
1>          [
1>              T=void (__cdecl *)(void)
1>          ]
1>          and
1>          [
1>              T=main::<lambda_c3c618d445b3cb24eede9bf304860ad7>::()::<lambda_4240e93016e3e420ff8383c9350ae130>
1>          ]
1>          and
1>          [
1>              T=void (__cdecl *)(void)
1>          ]
1>          Reason: cannot convert from 'A<T>' to 'A<T>'
1>          with
1>          [
1>              T=main::<lambda_c3c618d445b3cb24eede9bf304860ad7>::()::<lambda_4240e93016e3e420ff8383c9350ae130>
1>          ]
1>          and
1>          [
1>              T=void (__cdecl *)(void)
1>          ]
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

我已完成研究并在页面上查找错误消息 (link),但我仍然无法弄清楚问题所在。你能解释一下这个编译器错误吗?


编辑

这里肯定有些奇怪。如果我将main 中的代码更改为如下所示:

auto f = []()
{
    int* n = new int(0);
    auto g = [=](){ return *n; };
    *n++;
    return build<decltype(g)>(std::move(g));
};

我收到一条错误消息,提示 T=int (__cdecl *)(void) 在 build 调用中 - 这意味着 decltype(g) 正在给我一个函数指针?嗯?我正在按值捕获指针,然后对其进行修改 - 它不应该 来创建一个仿函数 - 并且一个没有转换为函数指针的指针吗?可能我有些不懂。

查看相关:Lambda expressions : n3290 draft


另外,如果这个 VS2012 编译器中的一个错误,你能想出一个解决方法吗?

【问题讨论】:

    标签: c++ templates visual-studio-2012 c++11 lambda


    【解决方案1】:

    我可以确认使用 GCC(在 linux 上),这段代码编译得很好。 所以我想说 VisualStudio 似乎是错误的根源。

    【讨论】:

      【解决方案2】:

      我没有要验证的 Windows 或 Visual Studio,对 C++ 中的 lambda 函数也没有太多经验,但也许您需要在函数中包含(尽管是空的)参数列表?即将第 21 行更改为

      return build([](){});
      

      两个版本都使用 GCC 编译,但也许 Visual Studio 更挑剔一些。

      我可能有的另一个问题是,您在第 24 行定义的 lambda 函数是否会起作用,因为它的返回值涉及您在函数本身内部定义的 lambda 函数。

      【讨论】:

      • 哦,我现在对其进行了标准化,感谢您指出这一点,因为它可能会使事情变得混乱。 VS2012 接受无输入语法就好了。
      • @Timothy:参数列表是可选的,最小的有效 lambda 表达式是[]{}。这不是问题。
      • @Xeo 我知道,最初我忽略了有效的参数列表。但它作为错误的可能来源引起了人们的注意,所以我想我会使用人们更熟悉的语法,以免分散注意力。
      • @Anthony 当您说“两个版本都使用 GCC 编译”时,您的意思是您已经采用了我提供的代码并成功构建了它吗?如果是这样,这对我来说是个重要消息,因为这可能意味着这是一个 VS2012 编译器错误。我不知道如何运行 GCC 来检查自己 - 如果您知道它使用 GCC 可以工作,那对我来说将是一个巨大的帮助! -- 我现在实际上正在下载 GCC,所以我可以尝试弄清楚如何自己做这种测试以备将来使用。
      • @TimothyShields:是的,对不起,我不是更清楚。无论有没有空参数列表,它都能在 Linux 上正常编译。
      【解决方案3】:

      我不知道该行为是否符合标准,但在 VC++ 2019 中,该错误仅在选项 /permissive- 时发生,然后在严格模式开启时发生。

      不过,这里是解决问题的方法,只需将 lambda 转换为引用类型:

      template <typename FUNC>
      void f(FUNC& o){}
      
      int main()
      {
          f((std::function<void()>&)[](){});
          // or also:
          auto func = [](){};
          f(func);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-08
        • 1970-01-01
        相关资源
        最近更新 更多