如何反转通过std::bind绑定的函数的布尔返回值?
嗨,我完全懂你想要的——一个不用重复写样板代码、能通用反转任意布尔返回值函数结果的方法,不管是直接调用的函数还是std::bind绑定后的对象。先说说你之前尝试遇到的问题,再给你几个实用的解决方案:
为什么你之前的实现和std::bind配合失败?
你写的InvertBooleanResult模板函数之所以报错,是因为std::bind会把整个绑定逻辑包装成一个复杂的_Bind类型 functor,而不是直接把原函数和参数传递给你的模板。当你尝试用std::bind(InvertBooleanResult, IsTheMagicNumber, ...)时,bind会把IsTheMagicNumber当作第一个参数传给InvertBooleanResult,而不是把它作为要调用的目标函数,这就导致最终生成的可调用对象签名和NumberValidator(bool(int))完全不匹配,编译器自然会抛出难以读懂的错误。
方案一:用C++17+标准库的std::not_fn(最优解)
其实STL早就为这个需求提供了现成工具——std::not_fn,它专门用来反转谓词的返回值,能适配所有可调用对象(函数指针、bind结果、lambda都可以)。用你的例子来说,代码可以简化成这样:
#include <functional> // 记得包含这个头文件 // 先定义好原绑定的验证器 NumberValidator check_is_magic = std::bind(IsTheMagicNumber, std::placeholders::_1, 42); // 一行代码反转结果 NumberValidator check_is_not_magic = std::not_fn(check_is_magic); // 测试验证 std::cout << std::boolalpha << check_is_not_magic(10) << std::endl; // 输出true std::cout << std::boolalpha << check_is_not_magic(42) << std::endl; // 输出false
这个方法完全不需要自己写额外的反转逻辑,简洁又符合STL规范,是C++17及以上版本的首选。
方案二:自己实现通用反转工具(兼容C++11/14)
如果还在用C++17之前的版本,没法用std::not_fn,可以自己写一个轻量的通用反转器:
template<typename Func> struct NotFunctor { Func func; explicit NotFunctor(Func f) : func(std::move(f)) {} template<typename... Args> auto operator()(Args&&... args) const -> decltype(!func(std::forward<Args>(args)...)) { return !func(std::forward<Args>(args)...); } }; // 辅助推导函数,简化调用 template<typename Func> NotFunctor<Func> make_not(Func f) { return NotFunctor<Func>(std::move(f)); }
使用方式和std::not_fn类似:
NumberValidator check_is_not_magic = make_not(std::bind(IsTheMagicNumber, std::placeholders::_1, 42));
这个实现用了完美转发和自动类型推导,能适配任意参数列表的布尔返回值函数。
方案三:用lambda的简洁写法(无需额外工具)
虽然你更倾向于bind的方式,但lambda其实也能写出非常简洁的代码,而且可读性拉满:
// 直接基于原函数反转 NumberValidator check_is_not_magic = [magic=42](int number) { return !IsTheMagicNumber(number, magic); }; // 或者基于已有的check_is_magic反转 NumberValidator check_is_not_magic = [&check_is_magic](int number) { return !check_is_magic(number); };
这种方式在C++11及以上都能用,不需要理解复杂的bind或模板细节,也是很实用的选择。
内容来源于stack exchange

