本篇分享详细解释一下 Top-level const 和 Low-level const 的概念。

Top-level 和 Low-level 指的是名称修饰符所处的位置,const 是最常见的修饰符,举一反三,便可知所有情况。

由例子切入理解:

int a = 42;
int b = 10;

int* const p1 = &a; // top-level const
*p1 = 22; // Ok
p1 = &b;  // Error!

int const* p2 = &a; // low-level const
*p2 = 22; // Error!
p2 = &b;  // Ok

p1 的类型为 a constant pointer to intp2 的类型为 a pointer to constant int。Top 和 Low 表示修饰符距实际类型的位置,前者修饰指针本身,后者修饰类型本身。因此,p1 可以改变 a 的值,但无法对指针再次绑定,p2 则完全相反。

大多数类型都支持 Top-level const,而 Low-level const 常出现于指针和引用类型。

首先应该着重强调的是引用类型。引用类型是个可以自动解引用的只读指针类型,下面两种是等价写法:

int a = 42;
int b = 10;

// reference type
int& ri = a;
ri = 22;

// equivalent with reference
int* const pi = &a;
*pi = 22;

Modern C++ 风格的代码几乎很少需要显式地使用指针类型,引用类型使用起来要更加简便和安全。

引用类型相当于自动添加了 Top-level const,可以手动再添加 Low-level const。指针类型则是相当特殊的一类,它可以同时添加二者。

// pi has both top-level const and low-level const
int const * const pi = &a;

它们之间最大的不同在于,Top-level const 可能会被忽略,而 Low-level const 永远不会被忽略。

第一种情境是对象拷贝。

int a = 42;
int const* const pi = &a;
int const* pc = pi; // ok, top-level const in pi is ignored
int* p  = pi; // error, low-level const in pi cannot be ignored

int const b = 10; // top-level const
int& r = b; // error, cannot bind a ordinary int& to a const int object
int const& rc = c; // ok

第二种情境是模板参数推导。

template <class T>
void f(T t) {}

int main() {
    int const i = 1; // top-level const

    // T deduced as int, f<int>(int)
    // top-level const is ignored.
    f(i);
}

第三种情境是 auto 类型推导。

int const b = 0; // top-level const is ignored.
auto c = b; // c is an int
static_assert(std::is_same_v<decltype(c), int>);

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use the Markdown in the comment form.