const 成员函数中模板成员的常量
Constness of template member in const member function
如何将 const
应用于 const
成员函数中的模板成员?我发现以下内容很有趣(这是在 VS15 中):
class TcpSocket;
class TcpThread
{
TcpSocket* Listener() const;
std::vector< TcpSocket* > sockets_;
};
TcpSocket* TcpThread::Listener() const
{
auto s = sockets_.front();
return s;
}
我添加了 auto
以阐明发生了什么。它被推断为 TcpSocket*
,因此正在选择 front
的非常量版本。但是,如果我插入
sockets_.erase(sockets_.begin());
作为第一行代码,它编译失败,本质上说 sockets_
是 const
.
它按原样工作是有意义的,但显然这里发生的不仅仅是“将每个成员视为 const
成员函数中的 const
。
即使 std::vector< TcpSocket* > sockets_;
是 本身 const
,容器(即 TcpSocket*
)是 而不是 const
.
这就是您获得非const
扣除的原因。
并不是调用了 front
的 non-const 版本,只是你在存储指针,然后将它放入 auto
中,它总是推导 by-value(而不是引用——你需要 auto& =
)。因为您正在复制 const 指针,所以您拥有自己的副本,因此省略了 const
,除非您以这种方式明确定义它。这就是为什么你推导 TcpSocket*
而不是 TcpSocket* const
.
如果您想验证这一点,请尝试执行 auto& s = _sockets.front()
并查看您得到的类型 然后。
注意。同样,因为你正在存储一个指针,所以你返回的 vector::const_reference
将指向一个 const 指针 而不是 指向 const 的指针.
container 本身在该范围内是 const,这意味着您无法更改其元素序列或它们指向的内容。所以你不能说 _sockets.erase()
也不能说 _sockets[0]
。 但是,因为元素本身是指向 non-const TcpSocket
的指针,这意味着您几乎可以用它们做任何您想做的事情。这是 容器 你不能 fiddle 用。
sockets_
在 Listener
里面是 const
。让我们看看 front
returns:
reference front();
const_reference front() const;
所以我们会得到 const_reference
,在本例中是 TcpSocket * const&
。
这是您的期望不正确的地方。为了清楚起见,去掉引用,你期望 const TcpSocket*
,它给你 TcpSocket * const
。前者是指向const TcpSocket
的指针,后者是const
指向TcpSocket
.
的指针
那么 front
给你的是一个指针,你无法将其更改为 可以 更改的 TcpSocket
。
因此,制作此指针的 non-const 副本及其指针对象可用于修改是完全有效的:
auto s = sockets_.front();
//sockets_.front() returns TcpSocket* const
//s copies it to a TcpSocket*
为什么你没有得到TcpSocket * const
:
虽然front()
returnsTcpSocket* const &
,但auto
推导为TcpSocket*
.
考虑:
double const & foo();
// ...
double const a = 4.0;
auto b = a; // valid, decltype(b) === double
double c = a; // valid, too
double d = foo(); // valid
auto e = foo(); // decltype(e) === double
反正你是在制作一个副本,那为什么那个副本是 const
?
s
成为 TcpSocket * const
.
不会让你得到任何有价值的东西
为什么你没有得到 TcpSocket const *
:
那只是因为您将 TcpSocket*
存储在向量中。 front()
的 const
确保存储的指针不被改变(即你不能使 sockets_.front()
从 Listener()
中指向另一个 TcpSocket
)但维护const
-指向的对象的正确性是由于用户。
如何将 const
应用于 const
成员函数中的模板成员?我发现以下内容很有趣(这是在 VS15 中):
class TcpSocket;
class TcpThread
{
TcpSocket* Listener() const;
std::vector< TcpSocket* > sockets_;
};
TcpSocket* TcpThread::Listener() const
{
auto s = sockets_.front();
return s;
}
我添加了 auto
以阐明发生了什么。它被推断为 TcpSocket*
,因此正在选择 front
的非常量版本。但是,如果我插入
sockets_.erase(sockets_.begin());
作为第一行代码,它编译失败,本质上说 sockets_
是 const
.
它按原样工作是有意义的,但显然这里发生的不仅仅是“将每个成员视为 const
成员函数中的 const
。
即使 std::vector< TcpSocket* > sockets_;
是 本身 const
,容器(即 TcpSocket*
)是 而不是 const
.
这就是您获得非const
扣除的原因。
并不是调用了 front
的 non-const 版本,只是你在存储指针,然后将它放入 auto
中,它总是推导 by-value(而不是引用——你需要 auto& =
)。因为您正在复制 const 指针,所以您拥有自己的副本,因此省略了 const
,除非您以这种方式明确定义它。这就是为什么你推导 TcpSocket*
而不是 TcpSocket* const
.
如果您想验证这一点,请尝试执行 auto& s = _sockets.front()
并查看您得到的类型 然后。
注意。同样,因为你正在存储一个指针,所以你返回的 vector::const_reference
将指向一个 const 指针 而不是 指向 const 的指针.
container 本身在该范围内是 const,这意味着您无法更改其元素序列或它们指向的内容。所以你不能说 _sockets.erase()
也不能说 _sockets[0]
。 但是,因为元素本身是指向 non-const TcpSocket
的指针,这意味着您几乎可以用它们做任何您想做的事情。这是 容器 你不能 fiddle 用。
sockets_
在 Listener
里面是 const
。让我们看看 front
returns:
reference front();
const_reference front() const;
所以我们会得到 const_reference
,在本例中是 TcpSocket * const&
。
这是您的期望不正确的地方。为了清楚起见,去掉引用,你期望 const TcpSocket*
,它给你 TcpSocket * const
。前者是指向const TcpSocket
的指针,后者是const
指向TcpSocket
.
那么 front
给你的是一个指针,你无法将其更改为 可以 更改的 TcpSocket
。
因此,制作此指针的 non-const 副本及其指针对象可用于修改是完全有效的:
auto s = sockets_.front();
//sockets_.front() returns TcpSocket* const
//s copies it to a TcpSocket*
为什么你没有得到TcpSocket * const
:
虽然front()
returnsTcpSocket* const &
,但auto
推导为TcpSocket*
.
考虑:
double const & foo();
// ...
double const a = 4.0;
auto b = a; // valid, decltype(b) === double
double c = a; // valid, too
double d = foo(); // valid
auto e = foo(); // decltype(e) === double
反正你是在制作一个副本,那为什么那个副本是 const
?
s
成为 TcpSocket * const
.
为什么你没有得到 TcpSocket const *
:
那只是因为您将 TcpSocket*
存储在向量中。 front()
的 const
确保存储的指针不被改变(即你不能使 sockets_.front()
从 Listener()
中指向另一个 TcpSocket
)但维护const
-指向的对象的正确性是由于用户。