如何从首个类型的第二个非类型参数推导该类型?及skipIf函数技术问询
解决从非类型参数推导首个模板类型的问题
嘿,我来帮你搞定这个C++模板参数推导的问题!你写的skipIf函数很实用,但确实存在需要手动指定TCharType的麻烦——毕竟谁不想少写点重复代码呢?下面就来说说怎么让编译器自动帮你推导这个类型。
核心问题分析
你的原模板定义是这样的:
template <typename TCharType, TCharType char_> std::basic_istream<TCharType>& skipIf(std::basic_istream<TCharType>& istream_) { /* ... */ }
这里的问题在于:非类型模板参数char_的类型依赖于第一个模板参数TCharType,但编译器无法从char_的值反向推导出TCharType——除非我们调整模板的定义方式,让推导逻辑变得清晰。
最优解决方案:C++17 auto非类型模板参数
C++17引入的auto非类型模板参数完美解决了这个问题。我们可以让编译器先推导char_的类型,再把这个类型和输入流的TCharType做匹配,修改后的代码如下:
/// <summary> /// Check whether next character in std::basic_istream is what expected. Skip it if so; otherwise, set fail flag. /// </summary> template <auto char_, typename TCharType = std::remove_cv_t<decltype(char_)>> std::basic_istream<TCharType>& skipIf(std::basic_istream<TCharType>& istream_) { if ((istream_ >> std::ws).peek() == static_cast<TCharType>(char_)) { istream_.ignore(); } else { istream_.setstate(std::ios_base::failbit); } return istream_; }
关键改进点
- 用
auto作为非类型参数char_的类型,编译器会自动从你传入的字符值(比如','或L',')推导出它的实际类型(char或wchar_t)。 - 给
TCharType设置默认值:std::remove_cv_t<decltype(char_)>,这样如果没有显式指定TCharType,它会自动和char_的类型保持一致。 - 增加了
static_cast<TCharType>(char_)的转换,避免当char_的类型和TCharType(虽然默认是一致的,但如果显式指定的话)不匹配时的类型问题。
调用示例
现在你可以这样简洁地调用函数,完全不用手动指定TCharType:
#include <iostream> int main() { std::string s; // 处理普通char类型的输入流 std::cin >> s >> skipIf<','>> s; // 处理宽字符类型的输入流 std::wstring ws; std::wcin >> ws >> skipIf<L','>> ws; }
兼容C++17之前版本的替代方案
如果你还在使用C11/C14,没法用auto非类型参数,可以借助辅助模板来实现推导:
// 辅助模板,用于关联字符类型和字符值 template <typename TCharType, TCharType char_> struct CharLiteral { static constexpr TCharType value = char_; }; // 推导用的函数模板 template <typename CharLit> auto skipIf(std::basic_istream<typename CharLit::value_type>& istream_) -> decltype(istream_) { using TCharType = typename CharLit::value_type; if ((istream_ >> std::ws).peek() == CharLit::value) { istream_.ignore(); } else { istream_.setstate(std::ios_base::failbit); } return istream_; } // 宏来简化字面量的包装(可选,只是为了调用更方便) #define CHAR_LIT(c) CharLiteral<decltype(c), c>
调用方式会变成这样:
std::cin >> s >> skipIf<CHAR_LIT(',')>> s;
虽然不如C++17的方案简洁,但也能实现自动推导的效果。
总结
C++17的auto非类型模板参数是解决这类问题最优雅的方式,它让模板参数推导更智能,代码更简洁。你的skipIf函数经过修改后,既能保持原有功能,又能大幅提升使用的便捷性。
内容的提问来源于stack exchange,提问作者Poeta Kodu
相关产品推荐
相关产品推荐

