以下代码在 Visual Studio 2017 中使用 MSVC 编译器进行编译,但无法在 GCC 或 Clang 中编译。
#include <iostream>
#include <functional>
void functionTest(std::function<void()>) {
std::cout << "F\n";
}
void functionTest(bool) {
std::cout << "B\n";
}
int main() {
functionTest([](){ std::cout << "wut"; });
}
为了解决这个问题,我们可以像这样使用 enable_if :
#include <iostream>
#include <functional>
void functionTest(std::function<void()>) {
std::cout << "F\n";
}
template<typename BOOL_TYPE, typename = typename std::enable_if<std::is_same<bool, BOOL_TYPE>::value>::type>
void functionTest(BOOL_TYPE) {
std::cout << "B\n";
}
int main() {
functionTest([](){ std::cout << "wut"; });
}
或者我可以通过引入用户类型而不是 bool 来消除歧义(这是在构造函数存在歧义问题的情况下需要执行的操作):
#include <iostream>
#include <functional>
void functionTest(std::function<void()>) {
std::cout << "F\n";
}
enum class DescriptiveTypeName {False, True};
void functionTest(DescriptiveTypeName) {
std::cout << "B\n";
}
int main() {
functionTest([](){ std::cout << "wut"; });
}
我在这里遇到的问题是我有一个非平凡大小的游戏项目,并且正在尝试在 Xcode 中为 iOS 进行编译。据我所知,我无法在所有编译器中获得 Visual Studio 展示的相同行为(这会很好)。因此,我试图编辑我的项目以使其更符合标准。
为了在 Visual Studio 中执行此操作,因为它是我的主要工作环境,我想知道正在使用哪个非标准扩展以及如何在可能的情况下禁用它。我可以尝试在 Xcode 中执行此操作,但是对于这个特定问题,我发现了很多模棱两可的问题,并且一次只能给我一些。
作为一个额外的好奇心,我想知道这个模棱两可的案例是否有任何标准建议来解决它,或者在这种情况下 Visual Studio 是否只是完全流氓。
最佳答案
lambda->bool 的转换其实就是 lambda->function pointer->bool。由于其中之一不符合“用户定义的转换”的条件,因此考虑双重转换。
在 MSVC 中,lambda 有多个 lambda-> 函数指针转换,每个调用约定一个。这不符合标准,其中函数指针没有附加到它们的调用约定类型。
在任何情况下,这都应该使 lambda->function pointer->bool 转换模棱两可(并触发错误),但是 MSVC 以某种方式决定将此歧义视为无效重载而不是错误,并选择没有歧义的那个。这似乎也违反了标准。
这两个标准违规一起产生了您想要的行为,这主要是偶然的。
我相信我们可以以符合标准的方式解决它,而不必在每个地方编写手动 SFINAE。这是一个尝试:
template<class T>
struct exactly {
T t;
template<class U, std::enable_if_t<std::is_same<T, std::decay_t<U>>{}, int> =0>
exactly( U&& u ):t(std::forward<U>(u)) {}
exactly():t() {}
exactly(exactly&&)=default;
exactly(exactly const&)=default;
operator T() const& { return t; }
operator T() && { return std::move(t); }
T& get()& { return t; }
T const& get() const& { return t; }
T get()&& { return std::move(t); }
};
现在使用:
void functionTest(exactly<bool> b) {
std::cout << "B\n";
}
live example 。
基本上我们将花哨的 SFINAE 移动到一个实用程序类中,从而避免 SFINAE 污染函数签名。
关于c++ - 当传入 Lambda 时,Visual Studio 2017 中的什么扩展可以消除 "bool"与 "std::function"的歧义?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45582048/