CppWeekly 05 nested namespace and std::clamp

这个系列是从这篇博客开始的,主要是复现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()的行为和预想的一致,一切皆是引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值