依赖模板类型参数的字符串字面量:日期解析类适配宽/普通字符串
解决模板类中适配普通/宽字符串格式字面量的问题
这问题我之前做跨字符集的日期解析时也碰到过!用模板复用普通/宽字符串的解析逻辑确实是最合理的选择,针对std::get_time需要对应类型格式字面量的核心需求,我们可以用模板特化来优雅解决,直接上可运行的代码示例:
方案一:辅助模板函数提供对应格式字符串
先写一个辅助模板函数,通过特化来返回不同字符类型的格式字面量:
#include <iostream> #include <sstream> #include <iomanip> #include <chrono> #include <stdexcept> // 基础模板,默认删除(只允许特化版本) template<typename CharT> constexpr const CharT* get_date_format() = delete; // 普通字符串版本特化 template<> constexpr const char* get_date_format<char>() { return "%Y-%m-%d"; // 普通字符格式字面量 } // 宽字符串版本特化 template<> constexpr const wchar_t* get_date_format<wchar_t>() { return L"%Y-%m-%d"; // 宽字符格式字面量 } // 通用日期解析模板类 template<typename CharT> class DateParser { public: using StringType = std::basic_string<CharT>; using StreamType = std::basic_istringstream<CharT>; static std::chrono::system_clock::time_point parse(const StringType& date_str) { std::tm tm{}; StreamType date_stream(date_str); // 传入对应类型的格式字符串,完美匹配get_time的参数要求 date_stream >> std::get_time(&tm, get_date_format<CharT>()); if (date_stream.fail()) { throw std::invalid_argument("Failed to parse date: invalid format"); } return std::chrono::system_clock::from_time_t(std::mktime(&tm)); } }; // 测试代码 int main() { try { // 测试普通字符串解析 auto time_point1 = DateParser<char>::parse("2024-06-15"); std::cout << "ASCII date parsed successfully\n"; // 测试宽字符串解析 auto time_point2 = DateParser<wchar_t>::parse(L"2024-06-15"); std::wcout << L"Wide date parsed successfully\n"; } catch (const std::exception& e) { std::cerr << e.what() << '\n'; } return 0; }
方案二:模板类静态常量特化
如果你觉得辅助函数有点冗余,也可以直接在模板类里定义静态常量,通过特化初始化:
template<typename CharT> class DateParser { public: using StringType = std::basic_string<CharT>; using StreamType = std::basic_istringstream<CharT>; // 静态格式常量,默认值(仅允许特化类型使用) static constexpr const CharT* date_format = nullptr; static std::chrono::system_clock::time_point parse(const StringType& date_str) { std::tm tm{}; StreamType date_stream(date_str); // 直接使用类内的静态格式常量 date_stream >> std::get_time(&tm, date_format); if (date_stream.fail()) { throw std::invalid_argument("Failed to parse date: invalid format"); } return std::chrono::system_clock::from_time_t(std::mktime(&tm)); } }; // 普通字符串版本特化常量 template<> constexpr const char* DateParser<char>::date_format = "%Y-%m-%d"; // 宽字符串版本特化常量 template<> constexpr const wchar_t* DateParser<wchar_t>::date_format = L"%Y-%m-%d";
核心思路说明
- 两种方案都是利用模板特化的特性,为不同的
CharT类型(char/wchar_t)提供完全匹配的格式字面量,完美适配std::get_time的const CharT* fmt参数要求。 - 模板类的解析逻辑完全复用,不需要复制粘贴两套几乎一样的代码,符合DRY(Don't Repeat Yourself)原则。
- 后续如果需要支持
char16_t/char32_t等其他字符类型,只需要新增对应的特化版本即可,扩展性极强。
内容的提问来源于stack exchange,提问作者Janis Norvelis
相关产品推荐
相关产品推荐

