C++如何实现支持类型/非类型参数的类模板及自定义可调用get工具
核心限制说明
C++ 当前标准(截至 C++23)仅支持函数模板基于模板参数类别(类型参数/非类型参数)重载,变量模板、类模板均不支持该类重载,所以你无法直接实现MyClass<int>和MyClass<2>共享同一个类模板名的写法,也无法直接定义同名变量模板同时接受类型和非类型参数。
实现方案
方案1:直接重载函数模板(推荐)
如果你需要的是和std::get完全一致的调用形式myns::get<2>(tup)、myns::get<int>(tup),直接重载函数模板即可,写法最简单也没有额外开销:
#include <tuple> #include <utility> namespace myns { // 匹配类型参数的重载 template <typename T> constexpr decltype(auto) get(auto&& tup) { return std::get<T>(std::forward<decltype(tup)>(tup)); } // 匹配索引非类型参数的重载 template <std::size_t I> constexpr decltype(auto) get(auto&& tup) { return std::get<I>(std::forward<decltype(tup)>(tup)); } }
调用示例:
std::tuple<int, std::string> sample_tup{10, "hello"}; // 按索引取 myns::get<0>(sample_tup); // 返回10 // 按类型取 myns::get<int>(sample_tup); // 返回10
方案2:支持独立可调用对象的妥协方案
如果你确实需要把get<2>/get<int>作为独立可调用对象传递(比如作为算法入参、赋值给变量),可以对类型参数做轻量包装来规避模板重载限制:
#include <tuple> #include <utility> #include <type_traits> namespace myns { template <typename T> struct type_wrap { using type = T; }; // 类型包装工具 template <typename T> constexpr type_wrap<T> t{}; template <auto Arg> constexpr auto get = []<typename Tup>(Tup&& tup) -> decltype(auto) { if constexpr (std::same_as<std::remove_cvref_t<decltype(Arg)>, std::size_t>) { // 入参是索引,走std::get的索引重载 return std::get<Arg>(std::forward<Tup>(tup)); } else { // 入参是包装后的类型,走std::get的类型重载 return std::get<typename decltype(Arg)::type>(std::forward<Tup>(tup)); } }; }
调用示例:
std::tuple<int, std::string> sample_tup{10, "hello"}; // 索引版本可直接用 auto get_idx0 = myns::get<0>; get_idx0(sample_tup); // 返回10 // 类型版本用t<>包装后使用 auto get_int = myns::get<myns::t<int>>; get_int(sample_tup); // 返回10
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

