这个系列是从这篇博客开始的,主要是复现Jason Turner的“C++ Weekly With Jason Turner”视频中的代码。
022 Nested namespaces
这个是C++17的新特性,可以创建嵌套的namespace时将他们连写在一起,有时候很方便。
namespace orgnization {
namespace component {
namespace subclass {
struct A {
};
}
}
}
namespace org::com::subc {
struct A {
};
}
int main() {
return 0;
}
std::clamp
以前总是需要自己实现的简单功能,现在是标准库的一部分了,名为std::clamp()
。但是根据经验,得测试一下这个std::clamp()
的行为,尤其是参数引用的行为在primitive type和non-primitive type之间的差异,并且这个行为与auto
关键字是如何互动的。
经测试,在使用auto
而非auto&
时:
- primitive type,例如
int
,参数的引用是不能传递给std::clamp()
的返回值的,无论测试对象返回本身的值或者上下限的值。 - non-primitive type,例如下述代码中的
strcut A
,std::clamp()
返回的上下限并不是输入参数的引用,两者并没有指向同一个对象。若std::clamp()
返回测试对象本身,那么将是输入参数的引用。
在使用auto&
时,返回值始终是输入参数的引用。
#include <algorithm>
#include <iostream>
#include "TypeName.hpp"
struct A {
explicit A(int v)
: val{v} {}
A (const A& other) = default;
friend bool operator < ( const A& first, const A& second ) {
return first.val < second.val;
}
int val;
};
static void test_auto_without_reference() {
int b = 10;
int c = 0;
int d = 5;
auto e = std::clamp( b, c, d );
std::cout << "Type of e is " << TYPE_NAME(e) << ", value is " << e << '\n';
int& f = d;
std::cout << "&d = " << &d << '\n';
std::cout << "&e = " << &e << '\n';
std::cout << "&f = " << &f << '\n';
std::cout << '\n';
int g = 3;
auto h = std::clamp( g, c, d );
std::cout << "d = -1 \n";
d = -1;
std::cout << "e = " << e << '\n';
std::cout << "f = " << f << '\n';
std::cout << '\n';
std::cout << "g = -1 \n";
g = -1;
std::cout << "&g = " << &g << '\n';
std::cout << "&h = " << &h << '\n';
std::cout << "h = " << h << '\n';
A objB(10);
A objC(0);
A objD(5);
auto objE = std::clamp( objB, objC, objD );
std::cout << "Type of objE is " << TYPE_NAME(objE) << '\n';
std::cout << "objE.val = " << objE.val << '\n';
A& objF = objD;
std::cout << "Type of objF is " << TYPE_NAME(objF) << '\n';
std::cout << "&objD = " << &objD << '\n';
std::cout << "&objE = " << &objE << '\n';
std::cout << "&objF = " << &objF << '\n';
std::cout << "Assign -1 to objD. \n";
objD.val = -1;
std::cout << "objE.val = " << objE.val << '\n';
std::cout << "objF.val = " << objF.val << '\n';
std::cout << '\n';
A objG(3);
auto objH = std::clamp( objG, objC, objD );
std::cout << "Type of objH is " << TYPE_NAME(objH) << '\n';
std::cout << "&objG = " << &objG << '\n';
std::cout << "&objH = " << &objH << '\n';
std::cout << "Assign -1 to objG. \n";
objG.val = -1;
std::cout << "objH.val = " << objH.val << '\n';
}
static void test_auto_with_reference() {
int b = 10;
int c = 0;
int d = 5;
auto& e = std::clamp( b, c, d );
std::cout << "Type of e is " << TYPE_NAME(e) << ", value is " << e << '\n';
int& f = d;
std::cout << "&d = " << &d << '\n';
std::cout << "&e = " << &e << '\n';
std::cout << "&f = " << &f << '\n';
std::cout << '\n';
int g = 3;
auto& h = std::clamp( g, c, d );
std::cout << "d = -1 \n";
d = -1;
std::cout << "e = " << e << '\n';
std::cout << "f = " << f << '\n';
std::cout << '\n';
std::cout << "g = -1 \n";
g = -1;
std::cout << "&g = " << &g << '\n';
std::cout << "&h = " << &h << '\n';
std::cout << "h = " << h << '\n';
A objB(10);
A objC(0);
A objD(5);
auto& objE = std::clamp( objB, objC, objD );
std::cout << "Type of objE is " << TYPE_NAME(objE) << '\n';
std::cout << "objE.val = " << objE.val << '\n';
A& objF = objD;
std::cout << "Type of objF is " << TYPE_NAME(objF) << '\n';
std::cout << "&objD = " << &objD << '\n';
std::cout << "&objE = " << &objE << '\n';
std::cout << "&objF = " << &objF << '\n';
std::cout << "Assign -1 to objD. \n";
objD.val = -1;
std::cout << "objE.val = " << objE.val << '\n';
std::cout << "objF.val = " << objF.val << '\n';
std::cout << '\n';
A objG(3);
auto& objH = std::clamp( objG, objC, objD );
std::cout << "Type of objH is " << TYPE_NAME(objH) << '\n';
std::cout << "&objG = " << &objG << '\n';
std::cout << "&objH = " << &objH << '\n';
std::cout << "Assign -1 to objG. \n";
objG.val = -1;
std::cout << "objH.val = " << objH.val << '\n';
}
int main() {
std::cout << "Hello, Clamp! \n";
// auto a = std::clamp( 1, 0.0, 2.0f ); // This is an error.
// auto a = std::clamp( 1, 0.0, 2.0 ); // This is also an error.
auto a = std::clamp( 1.0, 0.0, 2.0 );
std::cout << "Type of a is " << TYPE_NAME(a) << ", value is " << a << '\n';
test_auto_without_reference();
std::cout << "==========\n";
test_auto_with_reference();
return 0;
}
上述代码的输出如下
Hello, Clamp!
Type of a is double, value is 1
Type of e is int, value is 5
&d = 0x7fffece08168
&e = 0x7fffece0816c
&f = 0x7fffece08168
d = -1
e = 5
f = -1
g = -1
&g = 0x7fffece08170
&h = 0x7fffece08174
h = 3
Type of objE is A
objE.val = 5
Type of objF is A&
&objD = 0x7fffece08178
&objE = 0x7fffece0817c
&objF = 0x7fffece08178
Assign -1 to objD.
objE.val = 5
objF.val = -1
Type of objH is A
&objG = 0x7fffece08180
&objH = 0x7fffece08184
Assign -1 to objG.
objH.val = -1
==========
Type of e is const int&, value is 5
&d = 0x7fffece08174
&e = 0x7fffece08174
&f = 0x7fffece08174
d = -1
e = -1
f = -1
g = -1
&g = 0x7fffece08178
&h = 0x7fffece08178
h = -1
Type of objE is const A&
objE.val = 5
Type of objF is A&
&objD = 0x7fffece08180
&objE = 0x7fffece08180
&objF = 0x7fffece08180
Assign -1 to objD.
objE.val = -1
objF.val = -1
Type of objH is const A&
&objG = 0x7fffece08184
&objH = 0x7fffece08180
Assign -1 to objG.
objH.val = -1
注意,在使用auto
而不是auto&
时,e的值并不随上限d变化,h的值也不随输入值g变化。objE的值也不随上限objD变化,但是objH的值随输入objG变化(objH是objG的引用,但是TYPE_NAME()的输出不太正确)。
在使用auto&
时,std::clamp()
的行为和预想的一致,一切皆是引用。