如何优化C++17中判断字符串是否为ANSI转义序列的方法性能?
C++17下优化ANSI转义序列判断方法的性能
原代码说明
类定义
#include <string> enum class ANSI { first, generic }; template <class T_str> class foo { private: template <typename T> static constexpr bool is_escape( const T& str, ANSI&& flag ) { /* implementation */ } public: template <class T> void public_method( T str ) // T can be also an int, double etc... { if ( is_escape( str ) ) { /* do something */ } } };
is_escape方法实现
#include <string> #include <type_traits> template <typename T> static constexpr bool is_escape( const T& str, ANSI&& flag ) { if constexpr( std::is_convertible_v <T, std::basic_string_view<T_str>> && ! std::is_same_v<T, std::nullptr_t> ) { switch( flag ) { case( ANSI::first ): { return ( ! std::basic_string_view<T_str>( str ).rfind( "\033"s, 0 ) ) && ( std::basic_string_view<T_str>( str ).length() < 7 ); } case( ANSI::generic ): { return ( std::basic_string_view<T_str>( str ).find( "\033"s ) != std::basic_string_view<T_str>::npos ); } } } return false; }
优化方案(C++17兼容)
1. 消除重复的basic_string_view构造
原代码每次调用字符串方法都重新构造basic_string_view,提前构造一次可减少冗余开销;同时将字符串查找改为单个字符检查,避免字符串匹配的额外逻辑:
// 替换原if constexpr内的逻辑 auto sv = std::basic_string_view<T_str>(str); switch(flag) { case ANSI::first: // 直接检查首字符,替代rfind("\033", 0) return !sv.empty() && sv.front() == static_cast<T_str>('\033') && sv.size() < 7; case ANSI::generic: // 查找单个字符,比查找字符串更高效 return sv.find(static_cast<T_str>('\033')) != sv.npos; }
2. 用模板重载替代if constexpr分支
将类型判断逻辑移到模板重载上,编译期直接筛选匹配的类型,避免运行时分支:
// 针对可转换为basic_string_view<T_str>的类型 template <typename T> static constexpr std::enable_if_t<std::is_convertible_v<T, std::basic_string_view<T_str>>, bool> is_escape(const T& str, ANSI flag) { auto sv = std::basic_string_view<T_str>(str); switch(flag) { case ANSI::first: return !sv.empty() && sv.front() == static_cast<T_str>('\033') && sv.size() < 7; case ANSI::generic: return sv.find(static_cast<T_str>('\033')) != sv.npos; default: return false; // 补全default分支消除编译警告 } } // 针对其他类型的重载 template <typename T> static constexpr std::enable_if_t<!std::is_convertible_v<T, std::basic_string_view<T_str>>, bool> is_escape(const T&, ANSI) { return false; }
3. 优化枚举参数传递
枚举是小类型,直接传值替代右值引用,避免不必要的推导开销:
// 参数从ANSI&& flag改为ANSI flag static constexpr bool is_escape(const T& str, ANSI flag)
4. 统一字符类型匹配
将转义字符转换为与T_str一致的类型,避免跨字符类型的转换开销:
// 在foo类内定义常量 constexpr static T_str escape_char = static_cast<T_str>('\033'); // 使用时直接调用 return !sv.empty() && sv.front() == escape_char && sv.size() <7;
优化后完整代码
#include <string> #include <type_traits> enum class ANSI { first, generic }; template <class T_str> class foo { private: constexpr static T_str escape_char = static_cast<T_str>('\033'); template <typename T> static constexpr std::enable_if_t<std::is_convertible_v<T, std::basic_string_view<T_str>>, bool> is_escape(const T& str, ANSI flag) { auto sv = std::basic_string_view<T_str>(str); switch(flag) { case ANSI::first: return !sv.empty() && sv.front() == escape_char && sv.size() < 7; case ANSI::generic: return sv.find(escape_char) != sv.npos; default: return false; } } template <typename T> static constexpr std::enable_if_t<!std::is_convertible_v<T, std::basic_string_view<T_str>>, bool> is_escape(const T&, ANSI) { return false; } public: template <class T> void public_method(T str) { if (is_escape(str, ANSI::first)) { /* do something */ } } };
内容的提问来源于stack exchange,提问作者Gianluca Bianco
相关产品推荐
相关产品推荐

