C++14/17混合库支持std::optional时如何条件编译isEmpty函数
C++混合版本下std::optional的条件编译isEmpty实现
原实现失效原因
你写的SFINAE逻辑有两个核心问题:
- 代码中使用的
int_模板不属于C++标准库,未自定义的情况下会直接触发编译错误。 - SFINAE仅能处理模板参数替换阶段的失败,如果你在函数参数列表中直接写
const std::optional<T>&,当编译环境不支持C++17、没有std::optional类型时,编译器解析函数参数类型时就会抛出硬错误,根本不会进入模板参数替换流程,SFINAE机制完全不生效。
正确实现代码
首先兼容C++14环境补全基础工具,再通过类型检测trait实现正确的SFINAE约束:
#include <type_traits> #include <utility> // C++14环境手动实现void_t,C++17及以上可删除这段定义 template <typename...> using void_t = void; // 类型检测trait:判断入参类型是否为std::optional实例 template <typename T, typename = void_t<>> struct is_optional : std::false_type {}; template <typename T> struct is_optional<T, void_t< decltype(std::nullopt), typename T::value_type >> : std::is_same<T, std::optional<typename T::value_type>> {}; // 仅当入参是std::optional类型时启用该重载 template <typename T, typename std::enable_if<is_optional<T>::value, int>::type = 0> inline bool isEmpty(const T& v) { return !v; }
优化建议
如果你的编译环境支持__has_include预处理指令(主流编译器GCC5+、Clang3.6+、VS2017+均支持),可以增加一层头文件存在性判断,进一步降低无<optional>环境下的编译开销:
#if __has_include(<optional>) #include <optional> // 此处放置上面的is_optional trait定义和optional版本的isEmpty重载 #endif
注意:不要在函数参数列表中直接书写未确认存在的类型(比如
const std::optional<T>&),必须把对std::optional存在性的检测全部放到模板参数的SFINAE上下文中,才能正确触发替换失败而非编译错误。
内容的提问来源于stack exchange,提问作者user3612643
相关产品推荐
相关产品推荐

