调用hana::is_valid传入无参函数的应用场景及SFINAE适配疑问
Boost.Hana
is_valid 处理无参函数的疑问解答 如何传入无参函数使用is_valid?
这里的「无参函数」其实指的是无参的可调用对象(通常用lambda),你需要把要检查的无参表达式写在这个可调用对象的函数体里,再把它传给is_valid,最后调用is_valid返回的结果(加())来触发检查。
举个实际例子:如果要检查某个类型T是否有静态无参成员函数foo(),可以这么写:
#include <boost/hana.hpp> namespace hana = boost::hana; struct HasFoo { static void foo() {} }; struct NoFoo {}; template <typename T> constexpr bool has_static_foo() { // 无参lambda包裹要检查的表达式T::foo() auto checker = []() -> decltype(T::foo()) {}; return hana::is_valid(checker)(); // 调用is_valid返回的对象完成检查 } static_assert(has_static_foo<HasFoo>(), ""); static_assert(!has_static_foo<NoFoo>(), "");
这里的核心逻辑是:is_valid接收这个无参lambda后,会返回一个可调用对象;当你调用这个对象(())时,它会尝试实例化lambda的调用逻辑,判断T::foo()是否合法。
无参函数体的SFINAE依赖上下文怎么来?
你猜测和lambda捕获有关是完全正确的——关键是让无参可调用对象的函数体依赖于模板参数,这样才能形成SFINAE生效的上下文:
- 要么像上面的例子一样,lambda直接引用外部模板函数的参数
T,让T::foo()的有效性绑定到T的类型; - 要么通过lambda捕获外部的模板参数(比如在模板类/函数内部),让表达式的合法性依赖于这个参数。
如果无参函数的逻辑不依赖任何模板参数,那表达式要么永远合法,要么永远非法,根本不需要SFINAE来做检查。只有当表达式的有效性和某个模板参数绑定的时候,is_valid才能通过SFINAE机制在编译时判断结果,而不会触发编译错误。
再举一个捕获外部模板参数的场景:
template <typename T> void process() { // 捕获外部模板参数T,检查T的默认构造是否有效 auto is_default_constructible = hana::is_valid([]() -> decltype(T()) {}); static_assert(is_default_constructible(), "T must be default constructible"); } // 合法调用 process<int>(); // 编译失败(static_assert触发) // process<std::unique_ptr<int>>();
这里lambda的函数体T()依赖外部模板参数T,当T不可默认构造时,lambda的返回类型推导会失败,但is_valid内部通过SFINAE处理了这个失败,返回false,而不是直接报错。
内容的提问来源于stack exchange,提问作者Enlico
相关产品推荐
相关产品推荐

