Giter VIP home page Giter VIP logo

modern-cpp-templates-tutorial's Introduction

Modern C++ template

Anurag's GitHub stats

知乎 youtube

modern cpp

头像

Visitor Count

modern-cpp-templates-tutorial's People

Contributors

frederick-vs-ja avatar ksark avatar mq-b avatar mq-loser avatar ooolize avatar puji4810 avatar rossqaq avatar rsp4jack avatar zhuzhu9 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

modern-cpp-templates-tutorial's Issues

对形参包展开场所的补充

C++ 只允许在这几种语境下进行形参包展开

对于01函数模板使用的几个例子:

  •   template<typename...Args>
      void print(const Args&...args){    
          int _[]{ (std::cout << args << ' ' ,0)... };
      }

    是在花括号包围的初始化器中展开

  •   template<typename T,std::size_t N, typename...Args>
      void f(const T(&array)[N], Args...index) {
          print(array[index]...);
      }

    是在函数形参列表中展开

所以不能以如下方式通过形参包展开输出所有参数而要使用前面那种看起来有点奇怪的方式

template<typename ...Args>
void print(const Args &...args) {
    (std::cout << args << " ")...;
}

显式指定的模板实参与 ADL

C++20 前显式指定模板实参的语法不支持 ADL, C++20 起支持(WG21 P0846R0测试链接)。

namespace fvs {
template<class T>
const T& max(const T& l, const T& r)
{
    return l > r ? l : r;
}

struct S {};
}

int main()
{
    auto p = static_cast<fvs::S*>(nullptr);
    /* unqualified */max<fvs::S*>(p, p); // error until C++20; OK since C++20
}

可能可以增加一些内容探讨这里的兼容问题。

关于md

md的内容好像没有课程全,后续会更新吗

文档中的两个可能错误

  • 01函数模板.md:386行,文本指向的链接
    原文:
[参见](https://github.com/Mq-b/Loser-HomeWork/blob/main/C++CoreGuidelines/第4章-函数.md#f55-不要使用-va_arg-参数)

应改为:

[参见](https://github.com/Mq-b/Loser-HomeWork/blob/main/src/C++CoreGuidelines/第4章-函数.md#f55-不要使用-va_arg-参数)
  • 04模板全特化.md:153行,代码的注释
    原文:
    std::cout << s<char> << '\n'; // char

可能应改为:

    std::cout << s<char> << '\n'; // ??

关于约束的一个问题

我在尝试写一个运算符重载时遇到问题,我将代码简化后这是可以表现出问题的代码:

template<typename value_type>
    std::ostream &operator<<(std::ostream &os, const std::vector<value_type> &vec) requires requires(value_type val)
{
    std::cout << val;
} {
    // ...
    return os;
}

在进行测试的时候发现一维std::vector正常:

std::vector vec{1, 2, 3, 4, 5};
std::cout << vec;
// 可以通过编译

但是std::vector<std::vector>无法通过编译。

std::vector<std::vector<int> > vec2{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
std::cout << vec2;
// 编译失败

这个问题可以通过其他复杂的方式解决,我就是不明白为什么这个约束会不满足,这个模板推断应该是可以在编译期递归推断的,不明白这里为什么不行。

关于模板 std::uniform_int_distribution 在类内声明强制要求 写明<>的问题

struct {
    //  error C2955: “std::uniform_int_distribution”: 使用 类 模板 需要 模板 参数列表
    std::uniform_int_distribution distribution; 

     // right
    std::uniform_int_distribution<> distribution;
};

// right
auto lambda = [distribution = std::uniform_int_distribution{}] {
    std::uniform_int_distribution distribution;
    };

std::uniform_int_distribution distribution; // right

一个比较有意思的问题, 求解

concept判定时间

我自己在写程序的时候发现,concept的判断时间是在定义处,而不是在使用处,换言之,如果先定义了一个concept,之后写了一些代码,影响了concept判定条件,即使在之后使用这个concept,依然会按照修改之前的结果判定,这个是正常的吗。如果是正常的,是否应该强调一下?

`04模板全特化` 中“细节”代码注释描述错误

https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/md/%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/04%E6%A8%A1%E6%9D%BF%E5%85%A8%E7%89%B9%E5%8C%96.md

见细节部分的第三个代码块

//constexpr auto n3 = g<int>(0); // Error! 函数模板 f 所实例化的所有函数都不可编译期求值,它们都不以 constexpr 修饰

注释中的f应该为g

非常抱歉,由于我的疏忽留下了错误的链接地址,现已修正到正确的地址

函数模板形参/实参应该分为两类

这篇文章认为函数模板形参/实参应该分为两类:

  • 调用者必须在角括号中提供实参的,以及
  • 调用者必须不在角括号中提供实参的。

大体上我赞同这种区分。作者对 max/min 有自己明确倾向,他认为调用时不应该手动指定模板实参而应该使用显式转型。

@Mq-b 可以考虑下整合这里的建议。

01函数模板中的代码,gcc13.2 及以前的编译器运行存在 bug,已在 gcc14.1 被修复

https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/md/%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/01%E5%87%BD%E6%95%B0%E6%A8%A1%E6%9D%BF.md

template<typename T1,typename T2,typename RT = 
    decltype(true ? T1{} : T2{}) >
RT max(const T1& a, const T2& b) { // RT 是 std::string
    return a > b ? a : b;
}

在gcc不能运行
https://godbolt.org/z/685Y95vKW

T1,T2不一定是可{}构造的,应用declval,且去除引用返回
需改成如下

template<typename T1,typename T2,typename RT = 
    std::remove_reference_t< decltype(true ? 
    std::declval<T1>() : std::declval<T2>())> >
RT max(const T1& a, const T2& b) { // RT 是 std::string
    return a > b ? a : b;
}

https://godbolt.org/z/xd14YaPx6

`requires` 表达式中“类型要求”

众所周知,requires 表达式如果要使用类型要求,得在要求序列中写 typename,但是为何以下代码不需要,且结果正确,那它是什么?

#include <iostream>

template<typename T>
void f(T){
    constexpr bool v = requires{ T::type; };
    std::cout << std::boolalpha << v << '\n';
}

struct X { using type = void; };

int main(){
    f(1);   // false 因为 int::type 不是合法表达式
    f(X{}); // true 因为 X::type 是合法表达式
}

测试可通过编译。

但是如果这个 requires 表达式是用作定义 concept 的时候,不使用 typename 就有不符合预料的结果:

#include <iostream>

template<typename T>
concept C = requires{ T::type; };

struct X { using type = int; };

int main(){
    std::cout << std::boolalpha << C<int> << '\n'; // false
    std::cout << std::boolalpha << C<X> << '\n';   // false
}

测试
如果我们给概念(concept)C 的 requires 表达式中的 T::type 改成 typename T::type,那么运行结果就会变成:falsetrue测试

待决名查找规则中的示例解释

原文:

对于在模板的定义中所使用的非待决名,当检查该模板的定义时将进行无限定的名字查找。在这个位置与声明之间的绑定并不会受到在实例化点可见的声明的影响。而对于在模板定义中所使用的待决名它的查找会推迟到得知它的模板实参之时。此时,ADL 将同时在模板的定义语境和在模板的实例化语境中检查可见的具有外部连接的 (C++11 前)函数声明,而非 ADL 的查找只会检查在模板的定义语境中可见的具有外部连接的 (C++11 前)函数声明。(换句话说,在模板定义之后添加新的函数声明,除非通过 ADL 否则仍是不可见的。)如果在 ADL 查找所检查的命名空间中,在某个别的翻译单元中声明了一个具有外部连接的更好的匹配声明,或者如果当同样检查这些翻译单元时其查找会导致歧义,那么行为未定义。无论哪种情况,如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域(在定义点和实例化点都不会)。
很长,但是看我们加粗的就够:

  • 非待决名:检查该模板的定义时将进行无限定的名字查找
  • 待决名:它的查找会推迟到得知它的模板实参之时

我们这里简单描述一下:

this->f() 是一个待决名,这个 this 依赖于模板 X

所以,我们的问题可以解决了吗?

  1. this->f() 是待决名,所以它的查找会推迟到得知它模板实参之时(即知道父类是谁,可以访问父类)。
  2. f() 是非待决名,检查该模板的定义时将进行无限定的名字查找(不知道父类),按照正常的查看顺序,先类内(查找不到),然后全局(找到)。

是否需要修改掉 “即知道父类是谁,可以访问父类”、“不知道父类”这种不严谨的说法。

我感觉其实是上面概念中的最后一句话:

无论哪种情况,如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域

这句话可以解释为什么 f() 非待决名进行无限定名字查找找不到父类,因为它取决于模板形参,还未实例化。

this->f() 是待决名,查找会推迟到得知它模板实参之时,此时父类不再取决于模板形参,已经实例化了,就没有上面说的那个问题了。

这是否合理?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.