网站首页 文章专栏 从表达式左边推导模板参数
从表达式左边推导模板参数
编辑时间:2023-03-22 11:31:23 作者:qicosmos 6条评论


    出自:purecpp.cn

    地址: www.purecpp.cn

    转载请注明出处!


来说两句吧
登录才能发表评论。
最新评论
  • qicosmos
    zhenhua 2023-03-21 02:34:42
      assert(s == "42);

    少了返引号

      assert(s == "42");

  • qicosmos
    qicosmos 2023-03-22 11:31:38
    谢谢指出,已经修改。
  • qicosmos
    柒陆伍肆叁贰壹 2023-04-08 05:46:24
    还得上类模板
  • qicosmos
    hxbj 2023-04-08 06:46:26

    请问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

  • qicosmos
    loop 2023-04-10 05:47:41

    直接 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 {};}

  • qicosmos
    yingyulou 2023-05-05 01:26:54
    利用这一技术,可以做出一个更酷炫的功能:由于在发生operator T的时候,T的实际类型是已知的,所以,可以用多个这样的“适配器类”,去初始化一个聚合类,从而在初始化的同时,分别将这些T换成聚合类中的各个数据成员的实际类型。最终,就能利用这些类型,将一个结构体变量拆成一个元组。这一功能的完整实现比较复杂,不便于在评论区进行论述。
Absolutely

purecpp

一个很酷的modern c++开源社区


[社区开源项目列表,点击前往]


purecpp社区自2015年创办以来,以“Newer is Better”为理念,相信新技术可以改变世界,一直致力于现代C++研究、应用和技术创新,期望通过现代C++的技术创新来提高企业生产力和效率。


社区坚持只发表原创技术文章,已经累计发表了一千多篇原创C++技术文章;


组织了十几场的C++沙龙和C++大会,有力地促进了国内外C++开发者之间的技术交流;


开源了十几个现代C++项目,被近百家公司所使用,有力地推动了现代C++在企业中的应用。


期待更多的C++爱好者能参与到社区C++社区的建设中来,一起为现代C++开源项目添砖加瓦,一起完善C++基础设施和生态圈。


微信公众号:purecpp, 社区邮箱: purecpp@163.com


友情链接