CppWeekly 05 nested namespace and std::clamp
阿新 • • 發佈:2021-01-11
這個系列是從這篇部落格開始的,主要是浮現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()
的行為和預想的一致,一切皆是引用。