网站首页 文章专栏 从表达式左边推导模板参数
请问parse中的T推导规则是什么?我尝试在代码中使用,但除了std::string=parse(str);的这种用法,其它的都不正确.
编译器为 vs2022 msvc /std:c++latest
// 先声明再赋值 /*std::string s; s = parse(str);*///operator=不明确operator =(const _Elem)或operator =(const _Elem *const )... // 花括号初始化 std::string s{ parse(str) };//T推导为char
直接 std::string x = parse(content); 走的是拷贝初始化,没有重载决议问题,T 推导成 std::string。
先声明再赋值调用的是 operator=() 运算符重载,需要重载决议,只要赋值运算符有多个重载,T 就有二义性。
type y{parse(content)}; 走列表初始化(list-initialization):
1. 看 type 是不是聚合类型(aggregate-type),如果是就走聚合初始化
2. 如果 type 是 std::initializer_list,那么直接构造或者拷贝构造
3. 做两阶段判断:
a. 先对所有可以只接受一个 std::initializer_list 参数的构造函数(后续参数需要有默认值)做重载决议
b. a全部失败后对所有构造函数做重载决议
std::string y{parse(content)} 显然不符合 12,但同时符合 3.ab 这两个条件。
由于 3.a 优先于 3.b,所以 T 被推导成 std::initializer_list<char> 的参数 char。
要让例子成立,需要想办法让 3.a 重载决议失败,所以需要对 operator T() 做 sfinae 约束(constraint)。
约束需要禁止 T 被推导成 char,既 !std::same_as<T, char>。
要让例子 std::string z; z = parse(content); 成立,需要让 operator=() 重载决议中的所有情况刚好只有一个匹配成功。
由于 std::string 的 operator=() 里唯一的整形重载参数是 char,在上面已经禁用掉了,所以只需要按照例子里的两种分支情况允许(std::is_integral_v<T> || std::same_as<T, std::string>)通过即可。
parse(content) 返回模板同时 std::string 的 operator=() 或者构造函数接收模板的情况不会参加推导,但 sfinae。
约束后的函数声明:
template<typename T>
requires (!std::same_as<T, char> && (std::same_as<T, std::string> || std::is_integral_v<T>))
operator T(){return {};}
purecpp
一个很酷的modern c++开源社区
purecpp社区自2015年创办以来,以“Newer is Better”为理念,相信新技术可以改变世界,一直致力于现代C++研究、应用和技术创新,期望通过现代C++的技术创新来提高企业生产力和效率。
社区坚持只发表原创技术文章,已经累计发表了一千多篇原创C++技术文章;
组织了十几场的C++沙龙和C++大会,有力地促进了国内外C++开发者之间的技术交流;
开源了十几个现代C++项目,被近百家公司所使用,有力地推动了现代C++在企业中的应用。
期待更多的C++爱好者能参与到社区C++社区的建设中来,一起为现代C++开源项目添砖加瓦,一起完善C++基础设施和生态圈。
微信公众号:purecpp, 社区邮箱: purecpp@163.com
少了返引号