为什么 std::function 没有进行类型检查?
Why is type checking not happening for std::function?
#include <functional>
void toggleOk(bool& b) { b = !b; }
void toggleBroken(bool b) { b = !b; }
void toggleInt(int i) { i = !i; }
void tooManyParams(bool b, int i) { i = !b; }
int main()
{
typedef std::function<void(bool&)> CallbackType;
typedef std::function<void(bool)> WrongCallbackType;
CallbackType cb1 = [](bool b) { b = !b; }; // Should throw error - missing reference
CallbackType cb2 = toggleOk; // Ok
CallbackType cb3 = toggleBroken; // Should throw error - missing reference
CallbackType cb4 = toggleInt; // Should throw error - integer instead of bool
WrongCallbackType cb5 = toggleBroken; // Ok
CallbackType cb6 = cb5; // Type checking not even applying between std::functions
CallbackType cb7 = tooManyParams; // Only this statement throws error
return 0;
}
考虑上面的示例,它创建了一堆回调,这些回调将 reference 到 bool
作为参数。除了最后一个回调 cb7
,此代码可以编译并且 运行 很好,即使存储在回调对象中的大多数函数与 reference 或 参数类型.
我在 VS19/C++20 中遇到过这种行为,lambda 存储在 std::function
中,但是我已经用两个不同的 G++ 编译器尝试了这个例子 Windows ,启用了额外的诊断并使用 C++17/C++2a 和 none 甚至报告了一个警告。
我的问题是 - 这是预期的行为还是错误?为什么?
是的,这是 std::function
定义的行为
std::function
使用 扭曲几乎所有类型的可调用对象,并参数化为非常量、非引用非易失性参数和 return 类型可调用的。
您需要使用平面类型函数指针来获得代码中的预期错误
void toggleOk(bool& b) { b = !b; }
void toggleBroken(bool b) { b = !b; }
void toggleInt(int i) { i = !i; }
void tooManyParams(bool b, int i) { i = !b; }
int main()
{
// typedef std::function<void(bool&)> CallbackType;
// typedef std::function<void(bool)> WrongCallbackType;
using CallbackType = void(*)(bool&);
using WrongCallbackType = void(*)(bool);
CallbackType cb1 = [](bool b) { b = !b; }; // error
CallbackType cb2 = toggleOk; // Ok
CallbackType cb3 = toggleBroken; // error
CallbackType cb4 = toggleInt; // error
WrongCallbackType cb5 = toggleBroken; // Ok
CallbackType cb6 = cb5; // error
return 0;
}
现在上面的CallbackType
和WrongCallbackType
是不同的类型,会产生你预期的错误。
但是lambda的情况下只能使用函数指针类型(如上图),只有.
#include <functional>
void toggleOk(bool& b) { b = !b; }
void toggleBroken(bool b) { b = !b; }
void toggleInt(int i) { i = !i; }
void tooManyParams(bool b, int i) { i = !b; }
int main()
{
typedef std::function<void(bool&)> CallbackType;
typedef std::function<void(bool)> WrongCallbackType;
CallbackType cb1 = [](bool b) { b = !b; }; // Should throw error - missing reference
CallbackType cb2 = toggleOk; // Ok
CallbackType cb3 = toggleBroken; // Should throw error - missing reference
CallbackType cb4 = toggleInt; // Should throw error - integer instead of bool
WrongCallbackType cb5 = toggleBroken; // Ok
CallbackType cb6 = cb5; // Type checking not even applying between std::functions
CallbackType cb7 = tooManyParams; // Only this statement throws error
return 0;
}
考虑上面的示例,它创建了一堆回调,这些回调将 reference 到 bool
作为参数。除了最后一个回调 cb7
,此代码可以编译并且 运行 很好,即使存储在回调对象中的大多数函数与 reference 或 参数类型.
我在 VS19/C++20 中遇到过这种行为,lambda 存储在 std::function
中,但是我已经用两个不同的 G++ 编译器尝试了这个例子 Windows ,启用了额外的诊断并使用 C++17/C++2a 和 none 甚至报告了一个警告。
我的问题是 - 这是预期的行为还是错误?为什么?
是的,这是 std::function
std::function
使用
您需要使用平面类型函数指针来获得代码中的预期错误
void toggleOk(bool& b) { b = !b; }
void toggleBroken(bool b) { b = !b; }
void toggleInt(int i) { i = !i; }
void tooManyParams(bool b, int i) { i = !b; }
int main()
{
// typedef std::function<void(bool&)> CallbackType;
// typedef std::function<void(bool)> WrongCallbackType;
using CallbackType = void(*)(bool&);
using WrongCallbackType = void(*)(bool);
CallbackType cb1 = [](bool b) { b = !b; }; // error
CallbackType cb2 = toggleOk; // Ok
CallbackType cb3 = toggleBroken; // error
CallbackType cb4 = toggleInt; // error
WrongCallbackType cb5 = toggleBroken; // Ok
CallbackType cb6 = cb5; // error
return 0;
}
现在上面的CallbackType
和WrongCallbackType
是不同的类型,会产生你预期的错误。
但是lambda的情况下只能使用函数指针类型(如上图),只有