如何在函数模板中使用Parser别名模板实现通用Try函数?
通用Try函数模板的正确实现
要实现你想要的Try<Digit>(r, "0")调用方式,核心是把目标函数作为非类型模板参数传入,同时让编译器自动推导函数的返回类型,避免重复指定类型。以下是两种可行的实现方案:
方案1:C++17及以上(推荐,最简洁)
利用C++17引入的auto非类型模板参数,直接推导函数指针类型,再通过std::invoke_result_t获取函数返回类型:
#include <string> #include <type_traits> #include <stdexcept> #include <cctype> template<typename T> using Parser = T(* const)(std::string const &); char Digit(std::string const &str) { if (str.size() != 1 || !isdigit(str[0])) { throw std::invalid_argument("Not a digit"); } return str[0]; } template <auto p> bool Try(typename std::invoke_result_t<decltype(p), const std::string&>& result, const std::string& str) { static_assert(p != nullptr, "Parser cannot be null."); try { result = p(str); return true; } catch (const std::exception& e) { return false; } } int main() { char r; Try<Digit>(r, "0"); // 完全符合你的调用需求 }
说明:
template <auto p>:让编译器自动推导模板参数p的类型,这里p直接绑定Digit函数的指针。std::invoke_result_t<decltype(p), const std::string&>:通过函数指针类型和参数类型,自动推导函数的返回类型(此处为char),确保result的类型与函数返回值匹配。
方案2:兼容C++11/14
如果无法使用C++17,可以显式指定返回类型和函数指针作为模板参数,调用时需同时声明返回类型:
#include <string> #include <stdexcept> #include <cctype> template<typename T> using Parser = T(* const)(std::string const &); char Digit(std::string const &str) { if (str.size() != 1 || !isdigit(str[0])) { throw std::invalid_argument("Not a digit"); } return str[0]; } template <typename T, Parser<T> p> bool Try(T& result, const std::string& str) { static_assert(p != nullptr, "Parser cannot be null."); try { result = p(str); return true; } catch (const std::exception& e) { return false; } } int main() { char r; Try<char, Digit>(r, "0"); // 需显式指定返回类型T }
说明:
template <typename T, Parser<T> p>:先指定返回类型T,再指定符合Parser<T>类型的函数指针p。- 这种方式兼容更早的C++标准,但调用时需要额外显式声明返回类型。
核心要点
- 非类型模板参数直接绑定函数指针,确保编译期就能通过
static_assert检查函数是否为空。 - 利用类型推导或
std::invoke_result_t简化调用,避免重复编写返回类型代码。
内容的提问来源于stack exchange,提问作者heheheha
相关产品推荐
相关产品推荐

