C++17下无需auto简化声明ctre::regex_results变量的方法
问题
我使用C++17开发,需要声明如下结构的ctre::regex_results类型变量:
ctre::regex_results<const char*, ctre::captured_content<1, void>, ctre::captured_content<2, void> > mts; ctre::regex_results<const char*, ctre::captured_content<1, void>, ctre::captured_content<2, void>, ..., ctre::captured_content<8, void> > mts;
其中模板参数列表中ctre::captured_content的数量由编译时确定。我希望找到不使用auto、且不在块作用域声明模板的简化声明方式(块作用域声明模板会报错:a template declaration cannot appear at block scope)。所需类型由以下模板变量决定:
template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> static constexpr inline auto search = regular_expression<typename regex_builder<input>::type, search_method, ctll::list<singleline, Modifiers...>>();
附示例代码:
#include <bits/stdc++.h> #include "ctre.hpp" // single-header of compile-time-regular-expressions using namespace std; #define LINE_RGX "((?:a+).(?:b+).(?:c+).(?:d+)\\s*)+" #define RGX1 "(a+)\\.(b+)\\.(c+)\\.(d+)\\s*" #define RGX2 "(a+\\.b+)\\.(c+\\.d+)\\s*" static constexpr auto ctre_line_rgx = ctll::fixed_string{ LINE_RGX }; static constexpr auto ctre_rgx1 = ctll::fixed_string{ RGX1 }; static constexpr auto ctre_rgx2 = ctll::fixed_string{ RGX2 }; constexpr auto match_line(std::string_view sv) noexcept { return ctre::match<ctre_line_rgx>(sv); } constexpr auto search_rgx1(std::string_view sv) noexcept { return ctre::search<ctre_rgx1>(sv); } constexpr auto search_rgx2(std::string_view sv) noexcept { return ctre::search<ctre_rgx2>(sv); } int main() { string s = "aaa.b.ccccc.dddd a.b.c.d aaaa.bb.c.ddddd"; ctre::regex_results mlp = match_line(s); ctre::regex_results<const char*, ctre::captured_content<1, void>, ctre::captured_content<2, void>, ctre::captured_content<3, void>, ctre::captured_content<4, void> > mts1; ctre::regex_results<const char*, ctre::captured_content<1, void>, ctre::captured_content<2, void> > mts2; string_view _tmp = mlp.get<1>().to_view(); cout << "parsing fields: " << _tmp << endl; while ( _tmp.size() > 0 && (mts1 = search_rgx1(_tmp)).size() > 0) { cout << mts1.get<1>().to_view() << " -> " << mts1.get<2>().to_view() << " -> " << mts1.get<3>().to_view() << " -> " << mts1.get<4>().to_view() << endl; if (mts1.size() >= _tmp.size()) break; _tmp = _tmp.substr(mts1.size()); } _tmp = mlp.get<1>().to_view(); cout << "parsing fields: " << _tmp << endl; while ( _tmp.size() > 0 && (mts2 = search_rgx2(_tmp)).size() > 0) { cout << mts2.get<1>().to_view() << " -> " << mts2.get<2>().to_view() << endl; if (mts2.size() >= _tmp.size()) break; _tmp = _tmp.substr(mts2.size()); } }
示例中mts1、mts2的类型由对应正则表达式确定,请问能否通过缩写或C++技巧避免逐个指定ctre::captured_content<N, void>参数?
解决方案
方法1:全局/命名空间作用域定义类型别名
利用decltype推导search_rgx函数的返回值类型,在全局或命名空间作用域定义类型别名,随后在块作用域直接复用:
// 全局/命名空间作用域定义类型别名 using Mts1Type = decltype(search_rgx1(std::string_view{})); using Mts2Type = decltype(search_rgx2(std::string_view{})); int main() { string s = "aaa.b.ccccc.dddd a.b.c.d aaaa.bb.c.ddddd"; ctre::regex_results mlp = match_line(s); Mts1Type mts1; // 直接使用别名,无需手动编写模板参数 Mts2Type mts2; // 后续逻辑保持不变... }
该方式完全满足要求:不使用auto声明变量,块作用域无模板定义,类型由编译时自动推导且与正则表达式捕获组数量匹配。
方法2:封装通用类型推导模板
如果需要适配更多正则表达式,可在全局/命名空间作用域定义通用模板,快速提取对应regex_results类型:
template <ctll::fixed_string Regex> using RegexResultsType = decltype(ctre::search<Regex>(std::string_view{})); // 使用时指定目标正则表达式即可 using Mts1Type = RegexResultsType<ctre_rgx1>; using Mts2Type = RegexResultsType<ctre_rgx2>; int main() { Mts1Type mts1; Mts2Type mts2; // ... }
此方式扩展性更强,新增正则表达式时只需复用模板,无需重复编写decltype逻辑。
方法3:变量声明时直接用decltype初始化
若不想提前定义类型别名,可在变量声明时结合decltype和默认初始化,直接推导类型:
int main() { string s = "aaa.b.ccccc.dddd a.b.c.d aaaa.bb.c.ddddd"; ctre::regex_results mlp = match_line(s); decltype(search_rgx1(std::string_view{})) mts1{}; decltype(search_rgx2(std::string_view{})) mts2{}; // 后续逻辑保持不变... }
该方式无需额外全局类型定义,直接在变量声明阶段完成类型推导,同样满足不使用auto、块作用域无模板的要求。
内容的提问来源于stack exchange,提问作者tfwatt
相关产品推荐
相关产品推荐

