1. 程式人生 > 其它 >CppWeekly 05 nested namespace and std::clamp

CppWeekly 05 nested namespace and std::clamp

技術標籤:c++學習筆記c++

這個系列是從這篇部落格開始的,主要是浮現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 Astd::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()的行為和預想的一致,一切皆是引用。