1 引用限定符

学了这么多年C++,今天拜读了Scott Meyes的《more effective cpp》,第一次看到这种写法…

引用限定可以让成员函数只能被左值对象调用或者只能被右值对象调用
下面举例说明:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
namespace left_value {
    class Hello {
        void show() & {
            std::cout << "just for left-value\n";
        }
    };

    inline void run() {
        Hello t;
        t.show(); // ok

        Hello{}.show(); // compile error: passing 'left_value::Hello' as 'this' argument discards qualifiers [-fpermissive]
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
namespace right_value {
    struct Test {
        void show() && {
            std::cout << " just for right value\n";
        }
    };

    inline void run() {
        Test t;
        t.show(); //compile error: passing 'right_value::Test' as 'this' argument discards qualifiers [-fpermissive]

        Test{}.show();  //ok
    }
}

换句话说,引用限定所限定的就是*this,它可以让一些函数只被左值this调用或者右值this调用。

2 同名的左值+右值函数

可以定义多个同名函数,编译器会根据对象的属性,自动判断应该调用哪个函数; 和函数尾部的 const 用法类似。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
namespace both_LR_value {
    struct Hello {
        // 编译出错: 使用访问控制后, 裸的同名函数不能存在!
        // 原因:(裸的同名函数 =  左值函数+右值函数)
        /* void f() {
            std::cout << "hh\n";
        }*/
        void f() & {
            std::cout << "lvalue object\n";
        }
        void f() && {
            std::cout << "rvalue object\n";
        }
    };

    inline void run() {
        Hello t;
        t.f(); // lvalue
        Hello().f(); // rvalue
    }
}

3 引用限定符和const 结合

由于 C++ 编译器会对函数名进行mangle, 我们可以写出以下 4 个重载函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace use_with_const_overload {
    struct Hello {
        void f() & {
            std::cout << "lvalue object\n";
        }
        void f() && {
            std::cout << "rvalue object\n";
        }

        void f() const & {
            std::cout << "const lvalue object\n";
        }
        void f() const && {
            std::cout << "const rvalue object\n";
        }
    };

    inline void run() {
        Hello t;
        t.f(); // lvalue
        Hello().f(); // rvalue

        const Hello t3;
        t3.f();            // const lvalue
        std::move(t3).f(); // const rvalue
    }
}

总结

没有引用限定符之前,类的左值对象和右值对象,都可以访问其成员函数。
引用限定本质上属于:C++访问控制相关的语言特性。