如何实现C++函数自动将连续容器转换为proxy类型?
问题分析
编译失败的核心原因是C++模板参数推导不会考虑隐式用户定义转换。当前foo的参数是const proxy<T>&,当直接传入std::vector<std::vector<int>>时,编译器需要先将其隐式转换为proxy<std::vector<int>>,但这个转换发生在模板参数推导之后——推导阶段编译器只会尝试将传入类型与proxy<T>直接匹配,显然vector不是proxy的子类,因此推导失败。
解决方案
有两种简洁的修复方式,都能实现直接调用foo(vec)的需求:
方案一:添加foo的重载版本
新增一个接受任意ContiguousContainer的重载,内部构造proxy后调用原foo:
// 原foo保持不变 template<ContiguousContainer T> int foo(const proxy<T>& temp){ return 1; } // 新增重载,处理直接传入容器的情况 template<ContiguousContainer V> int foo(const V& v) noexcept { return foo(proxy(v)); // 显式构造proxy后转发 }
方案二:修改foo的模板参数为容器类型
直接让foo接受符合ContiguousContainer的容器,内部构造proxy使用:
// 修改后的foo,直接接受容器类型 template<ContiguousContainer V> int foo(const V& v){ proxy<typename V::value_type> p(v); // 这里可以直接使用p的成员,或保留原逻辑 return 1; }
验证代码(方案一示例)
修改后的完整代码如下:
#include <iostream> #include <array> #include <vector> #include <span> #include <cstdint> #include <string> template <typename T> constexpr auto type_name() { std::string_view name, prefix, suffix; #ifdef __clang__ name = __PRETTY_FUNCTION__; prefix = "auto type_name() [T = "; suffix = "]"; #elif defined(__GNUC__) name = __PRETTY_FUNCTION__; prefix = "constexpr auto type_name() [with T = "; suffix = "]"; #elif defined(_MSC_VER) name = __FUNCSIG__; prefix = "auto __cdecl type_name<"; suffix = ">(void)"; #endif name.remove_prefix(prefix.size()); name.remove_suffix(suffix.size()); return name; } template <typename T> concept ContiguousContainer = requires (T t) { t.data(); t.size(); }; template<typename T> struct proxy{ template<typename V> proxy( const V & v ) noexcept : m_size( v.size() ) , m_ptr( v.data() ) {} std::size_t m_size; const T* m_ptr; }; template<typename V> proxy(const V &v) noexcept -> proxy<typename V::value_type>; template<ContiguousContainer T> int foo(const proxy<T>& temp){ return 1; } // 新增重载 template<ContiguousContainer V> int foo(const V& v) noexcept { return foo(proxy(v)); } int main(){ std::vector<std::vector<int>> vec; auto temp_0 = foo<decltype(vec)::value_type>(vec); auto temp_1 = proxy(vec); // 正常工作 std::cout << type_name<decltype(temp_1)>() << std::endl; auto temp_2 = foo(vec); // 现在可正常编译运行 return 0; }
修改后,foo(vec)会匹配到新增的重载,显式构造proxy后转发给原foo,既保留了原有的proxy使用逻辑,又实现了自动转换的需求。
内容的提问来源于stack exchange,提问作者Krupip
相关产品推荐
相关产品推荐

