mq-b / modern-cpp-templates-tutorial Goto Github PK
View Code? Open in Web Editor NEW现代C++模板教程
Home Page: https://mq-b.github.io/Modern-Cpp-templates-tutorial/
License: Other
现代C++模板教程
Home Page: https://mq-b.github.io/Modern-Cpp-templates-tutorial/
License: Other
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 << " ")...;
}
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的内容好像没有课程全,后续会更新吗
白老师 看一下这个示例 有什么问题
出处:变量模板-->使用变量模板
https://godbolt.org/z/Yovr6PvE5
倒也不是真不能分,但是会很麻烦,如何用比较简单的语言稍微聊一下。
因为感觉单独的说一句:模板不能分文件。很突兀,其他原因又挺麻烦的。
[参见](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-参数)
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;
// 编译失败
这个问题可以通过其他复杂的方式解决,我就是不明白为什么这个约束会不满足,这个模板推断应该是可以在编译期递归推断的,不明白这里为什么不行。
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,依然会按照修改之前的结果判定,这个是正常的吗。如果是正常的,是否应该强调一下?
如果这是你的个人 癖好请去掉,如果不是请解释不这样可能在哪些情形下导致什么后果.
见细节部分的第三个代码块
//constexpr auto n3 = g<int>(0); // Error! 函数模板 f 所实例化的所有函数都不可编译期求值,它们都不以 constexpr 修饰
注释中的f
应该为g
非常抱歉,由于我的疏忽留下了错误的链接地址,现已修正到正确的地址
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;
}
众所周知,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
,那么运行结果就会变成:false
、true
;测试。
原文:
对于在模板的定义中所使用的非待决名,当检查该模板的定义时将进行无限定的名字查找。在这个位置与声明之间的绑定并不会受到在实例化点可见的声明的影响。而对于在模板定义中所使用的待决名,它的查找会推迟到得知它的模板实参之时。此时,ADL 将同时在模板的定义语境和在模板的实例化语境中检查可见的具有外部连接的 (C++11 前)函数声明,而非 ADL 的查找只会检查在模板的定义语境中可见的具有外部连接的 (C++11 前)函数声明。(换句话说,在模板定义之后添加新的函数声明,除非通过 ADL 否则仍是不可见的。)如果在 ADL 查找所检查的命名空间中,在某个别的翻译单元中声明了一个具有外部连接的更好的匹配声明,或者如果当同样检查这些翻译单元时其查找会导致歧义,那么行为未定义。无论哪种情况,如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域(在定义点和实例化点都不会)。
很长,但是看我们加粗的就够:
- 非待决名:检查该模板的定义时将进行无限定的名字查找
- 待决名:它的查找会推迟到得知它的模板实参之时
我们这里简单描述一下:
this->f()
是一个待决名,这个this
依赖于模板X
。所以,我们的问题可以解决了吗?
this->f()
是待决名,所以它的查找会推迟到得知它模板实参之时(即知道父类是谁,可以访问父类)。f()
是非待决名,检查该模板的定义时将进行无限定的名字查找(不知道父类),按照正常的查看顺序,先类内(查找不到),然后全局(找到)。
是否需要修改掉 “即知道父类是谁,可以访问父类”、“不知道父类”这种不严谨的说法。
我感觉其实是上面概念中的最后一句话:
无论哪种情况,如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域
这句话可以解释为什么 f()
非待决名进行无限定名字查找找不到父类,因为它取决于模板形参,还未实例化。
this->f()
是待决名,查找会推迟到得知它模板实参之时,此时父类不再取决于模板形参,已经实例化了,就没有上面说的那个问题了。
这是否合理?
为什么作业只有一个
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.