能否将std::get别名为as?C++函数模板别名实现疑问
实现
as<T>(variant)替代std::get<T>(variant)的方法 你的判断有一半是对的:确实不能直接用using给std::get这个函数模板创建别名,但这并不代表没法实现as<bool>(my_variant)这种调用方式——我们可以用转发模板函数来达到类似效果。
为什么直接using行不通?
C++里的using别名规则确实不支持直接给函数模板起别名:using as = std::get;这种写法会编译失败,因为std::get是一个模板家族,编译器无法确定你要绑定到哪个具体的实例(毕竟std::get既支持按类型获取variant的值,也支持按索引获取)。而你提到的“函数指针只能由特定模板实例化生成”也没错,但这不是实现需求的必要路径。
最简单的实现方式:写转发模板函数
我们可以自己封装一个as模板函数,把调用直接转发给std::get,这样就能实现你想要的语法:
#include <variant> // 处理非const左值引用的variant template <typename T, typename... Ts> constexpr decltype(auto) as(std::variant<Ts...>& var) { return std::get<T>(var); } // 处理const左值引用的variant template <typename T, typename... Ts> constexpr decltype(auto) as(const std::variant<Ts...>& var) { return std::get<T>(var); } // 处理右值引用的variant template <typename T, typename... Ts> constexpr decltype(auto) as(std::variant<Ts...>&& var) { return std::get<T>(std::move(var)); }
使用的时候就和你预想的完全一样:
std::variant<int, bool, std::string> my_variant = true; bool v = as<bool>(my_variant); // 正常编译,行为和std::get<bool>一致
扩展:支持按索引获取(和std::get<I>对齐)
如果想要和std::get的功能完全对齐,还可以重载一个按索引模板参数调用的版本:
// 非const左值版本 template <std::size_t I, typename... Ts> constexpr decltype(auto) as(std::variant<Ts...>& var) { return std::get<I>(var); } // const左值版本 template <std::size_t I, typename... Ts> constexpr decltype(auto) as(const std::variant<Ts...>& var) { return std::get<I>(var); } // 右值版本 template <std::size_t I, typename... Ts> constexpr decltype(auto) as(std::variant<Ts...>&& var) { return std::get<I>(std::move(var)); }
这样as<0>(my_variant)也能正常使用,和std::get<0>效果相同。
总结
你关于“无法用using给函数模板别名”的结论是正确的,但通过封装转发模板函数,我们完全可以实现你想要的as<T>(variant)语法——这是C++中模拟函数模板“别名”最常用的技巧,既简洁又能保留原函数的所有特性。
内容的提问来源于stack exchange,提问作者sandwood
相关产品推荐
相关产品推荐

