使用 Visual Studio 2017 年的编译器在 C++17 中使用 lambda 编译 Kevlin Henney 的 Fizzbuzz
Compiling Kevlin Henney's Fizzbuzz with the use of lambdas in C++17 using Visual Studio 2017's compiler
我在编程时关注 Kevlin Henney's Youtube video Lambdas。在他的视频中大约 20:30 - 20:40 处,他给出了以下代码片段:
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 同时支持 lambdas
和 std::function<T>
,但这种类型的实现或用法是否特定于较新版本的编译器?意思是这种技术或用法仅适用于 C++20 及更高版本吗?如果是这样,可以对这个代码片段做些什么,以便它可以在 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
当存在 /permissive-
标志时,MSVC 似乎在处理三元语句的推导方面存在问题。 /permissive-
标志 应该 强制 MSVC 使用 strict standards conformance, however ironically this appears to be breaking what 编译。
这可以很容易地在编译器资源管理器上重现:Live Example. This appears to be fixed in newer MSVC versions with v19.25 onward Live Example
不幸的是,由于这是一个编译器错误,因此几乎没有办法解决这个问题。
您仅限于:
- 正在更新您的编译器,
- 删除
/permissive-
,或
- 不使用 return 不同类型的三元语句(例如,使用具有不同 return 的
if
/else
)
这是一个错误;如果 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;
};
应该可以。
我在编程时关注 Kevlin Henney's Youtube video Lambdas。在他的视频中大约 20:30 - 20:40 处,他给出了以下代码片段:
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 同时支持 lambdas
和 std::function<T>
,但这种类型的实现或用法是否特定于较新版本的编译器?意思是这种技术或用法仅适用于 C++20 及更高版本吗?如果是这样,可以对这个代码片段做些什么,以便它可以在 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
当存在 /permissive-
标志时,MSVC 似乎在处理三元语句的推导方面存在问题。 /permissive-
标志 应该 强制 MSVC 使用 strict standards conformance, however ironically this appears to be breaking what
这可以很容易地在编译器资源管理器上重现:Live Example. This appears to be fixed in newer MSVC versions with v19.25 onward Live Example
不幸的是,由于这是一个编译器错误,因此几乎没有办法解决这个问题。 您仅限于:
- 正在更新您的编译器,
- 删除
/permissive-
,或 - 不使用 return 不同类型的三元语句(例如,使用具有不同 return 的
if
/else
)
这是一个错误;如果 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;
};
应该可以。