【问题标题】:Compiling Kevlin Henney's Fizzbuzz with the use of lambdas in C++17 using Visual Studio 2017's compiler使用 Visual Studio 2017 的编译器在 C++17 中使用 lambda 编译 Kevlin Henney 的 Fizzbuzz
【发布时间】:2021-01-26 04:05:45
【问题描述】:

我在 Lambdas 上关注 Kevlin Henney's Youtube video 进行编程。在大约 20:30 - 20:40 在他的视频中,他给出了这个代码 sn-p:

string fizzbuzz(int n)
{
    auto fizz = [=](function<string(string)> f)
    {
        return n % 3 == 0 ? [=](auto) {return "Fizz" + f("");} : f;
    };
    auto buzz = [=](function<string(string)> f)
    {
        return n % 5 == 0 ? [=](auto) {return "Buzz" + f("");} : f;
    };
    auto id = [](auto s) { return s; };
    return fizz(buzz(id))(to_string(n));
}

这是我在 IDE 中的实际代码:

#include <functional>
#include <iostream>
#include <string>

std::string fizzbuzz(int n) {
    auto fizz = [=](std::function<std::string(std::string)> f) {
        return n % 3 == 0 ? [=](auto) { return "Fizz" + f(""); } : f;
    };
    auto buzz = [=](std::function<std::string(std::string)> f) {
        return n % 5 == 0 ? [=](auto) { return "Buzz" + f(""); } : f;
    };
    auto id = [](auto s) { return s; };
    return fizz(buzz(id))(std::to_string(n));
}

int main() {
    for (int i = 1; i <= 100; i++)
        std::cout << fizzbuzz(i) << '\n';
    return 0;
}

但是,当我尝试编译此 Visual Studio 时,会生成以下编译器错误:

1>------ Build started: Project: Data Structure Samples, Configuration: Debug x64 ------
1>main.cpp
1>c:\...\main.cpp(62): error C2445: result type of conditional expression is ambiguous: types 'fizzbuzz::<lambda_9027e592dd51e6f4c5342b61ff8c23f0>::()::<lambda_2463463a8046fa170a40e78d59e9f461>' and 'std::function<std::string (std::string)>' can be converted to multiple common types
1>c:\...\main.cpp(62): note: could be 'fizzbuzz::<lambda_9027e592dd51e6f4c5342b61ff8c23f0>::()::<lambda_2463463a8046fa170a40e78d59e9f461>'
1>c:\...\main.cpp(62): note: or       'std::function<std::string (std::string)>'
1>c:\...\main.cpp(65): error C2445: result type of conditional expression is ambiguous: types 'fizzbuzz::<lambda_c18a2fee5ba13240be9b86f815911a7c>::()::<lambda_2774da13f447e3dfb583778d4ea6d5bd>' and 'std::function<std::string (std::string)>' can be converted to multiple common types
1>c:\...\main.cpp(65): note: could be 'fizzbuzz::<lambda_c18a2fee5ba13240be9b86f815911a7c>::()::<lambda_2774da13f447e3dfb583778d4ea6d5bd>'
1>c:\...\main.cpp(65): note: or       'std::function<std::string (std::string)>'
1>c:\...\main.cpp(68): error C2664: 'void fizzbuzz::<lambda_9027e592dd51e6f4c5342b61ff8c23f0>::operator ()(std::function<std::string (std::string)>) const': cannot convert argument 1 from 'void' to 'std::function<std::string (std::string)>'
1>c:\...\main.cpp(68): note: Expressions of type void cannot be converted to other types
1>Done building project "Data Structure Samples.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

当我对照 CompilerExplorer 进行检查时发现 here,此代码可使用所有三个主要编译器编译:GCC、Clang 和 MSVC...

我知道 C++17 支持lambdasstd::function&lt;T&gt;,但是这种类型的实现或用法是否特定于较新版本的编译器?意思是这种技术或用法仅适用于 C++20 及更高版本吗?如果是这样,可以对这段代码 sn-p 做什么,以便它可以在 Visual Studio 2017 下使用提供相同语义和行为的 C++17 进行编译?


编辑

以下是我的编译器关于 C/C++ 语言部分的所有命令行设置:

/JMC /permissive- /GS /W3 /Zc:wchar_t /Qspectre /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc141.pdb" /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /std:c++latest /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\Data Structure Samples.pch" /diagnostics:classic

【问题讨论】:

  • 我不是在询问编译器错误,它们相当简单,我当前的编译器和设置抱怨参数不明确。我只是在找工作!
  • 仅供参考:我的编译器语言标志设置为:ISO C++ Latest Draft Standard (/std:c++latest)。似乎自动类型推导在这些 lambda 的上下文或它们的实现方式中不起作用......
  • 从您所描述的设置来看,我看不出这应该失败的原因。从三元表达式推断返回类型似乎存在问题,因为一个分支返回 std::function 而另一个返回 lambda。你的 Visual Studio 是什么版本? Compiler-Explorer 仅支持最旧的“2017 Update 9”,所以我想知道您是否使用的是具有推断错误的过时版本
  • 15.9.24 我认为应该足够新来支持这个... Compiler Explorer 上最旧的 MSVC 版本是 v19.14 我认为它应该对应于 Visual Studios 版本 15.7.5,它接受此代码。不幸的是,我不确定为什么这不起作用。我唯一的猜测是当前语言版本的设置不正确(您所说的应该设置为/std:c++latest)。希望其他人能够捕捉到我没有看到的东西
  • 我可能在older question 中发现了类似的问题。当时的 Visual Studios 2017 RC 似乎没有正确确定三元语句的结果表达式。我猜这是 MSVC 版本中的一个问题。不幸的是,MSVC 因没有按照规范正确实现 C++ 而臭名昭著

标签: c++ lambda compiler-errors visual-studio-2017 c++17


【解决方案1】:

这是一个错误;如果b 可以转换为c 类型的右值,则a?b:c 是合法的,反之亦然(除其他规则外)。

修复:

auto fizz = [=](std::function<std::string(std::string)> f) {
    if(n%3 == 0)
      f = [=](auto) { return "Fizz" + f(""); };
    return f;
};
auto buzz = [=](std::function<std::string(std::string)> f) {
    if(n % 5 == 0)
      f = [=](auto) { return "Buzz" + f(""); };
    return f;
};

应该可以的。

【讨论】:

  • 我得去看看!
  • 这个实现成功了!!!因此,MSVC 2017 作为编译器错误生成的歧义实际上是编译器本身的一个错误!!!
【解决方案2】:

当存在/permissive- 标志时,MSVC 似乎在处理三元语句的推导方面存在问题。 /permissive- 标志应该强制 MSVC 使用 strict standards conformance 编译,但具有讽刺意味的是,这似乎破坏了 should be valid code

这可以在 Compiler Explorer 上轻松复制:Live Example。这似乎在具有 v19.25 及更高版本的较新 MSVC 版本中得到修复 Live Example


不幸的是,由于这是一个编译器错误,因此几乎没有解决此问题的方法。 您仅限于:

  • 更新编译器,
  • 删除/permissive-,或
  • 不使用返回不同类型的三元语句(例如,使用具有不同返回的if/else

【讨论】:

  • 这允许代码通过更改/permissive- 标志来编译、构建和运行,但是,我通过for loop 运行它时得到的输出在每一行打印FizzBuzz输出...这就是为什么我给你一个赞成票但不接受这是我的问题的解决方案。
  • @FrancisCugler 代码应该生成correct output。由于 MSVC 似乎对来自/permissive- 的诊断感到厌烦,我猜想生成的代码也必须是厌烦的。无论哪种方式,这将是当时不同 SO 问题的主题。我只能建议在升级编译器之前避免这种模式
  • 使用ternary 语句的想法是在Kevlin 在他的视频中解释的代码的每次迭代中减少conditional checks 的数量...,删除/permissive- 标志有效在编译但产生无效的输出,并更新我的编译器,我已经在之前的评论中说明了这种情况......但我非常感谢你的时间和精力帮助我跟踪和缩小这个错误!
  • 最终,当我开始备份我的数据、擦除我的驱动器并安装一个完全干净的操作系统时,我将以最小的 Visual Studio 2019 安装...我什至可能会考虑拥有一个要安装的 GCC 或 Clang 版本...
猜你喜欢
  • 2020-03-19
  • 1970-01-01
  • 2017-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多