4

编辑:

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

2014 年 11 月 11 日:微软回应称,这个错误的修复应该出现在 Visual C++ 的下一个主要版本中。


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

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

#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 作为函数的模板T类型build。我得到的错误信息是:

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

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


编辑

这里肯定有些奇怪。如果我将代码更改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 表达式:n3290 草案


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

4

3 回答 3

3

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

于 2013-05-22T17:33:58.697 回答
2

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

return build([](){});

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

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

于 2013-05-21T04:23:17.020 回答
0

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

然而,这里是如何解决这个问题,只需将 lambda 转换为引用类型:

template <typename FUNC>
void f(FUNC& o){}

int main()
{
    f((std::function<void()>&)[](){});
    // or also:
    auto func = [](){};
    f(func);
}
于 2019-04-12T23:11:36.160 回答