【问题标题】:Constness of template member in const member functionconst 成员函数中模板成员的常量
【发布时间】:2016-05-01 22:03:44
【问题描述】:

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

【问题讨论】:

  • const 在成员函数声明的末尾意味着函数没有改变对象,所以如果你改变成员变量编译器会给你一个错误,第一个例子只是复制它允许它复制到非 const 版本

标签: c++ function templates constants member


【解决方案1】:

sockets_ 里面的Listenerconst。让我们看看front 返回的内容:

reference front();
const_reference front() const;

所以我们会得到一个const_reference,在本例中是一个TcpSocket * const&amp;

这是您的期望不正确的地方。为了清楚起见,去掉参考,你期望一个const TcpSocket*,它给你一个TcpSocket * const。前者是指向const TcpSocket 的指针,后者是指向TcpSocketconst 指针。

所以front 给你的是一个指针,你不能更改为TcpSocket,你可以更改。

因此,制作此指针的非常量副本及其指针可用于修改是完全有效的:

auto s = sockets_.front();
//sockets_.front() returns TcpSocket* const
//s copies it to a TcpSocket*

【讨论】:

  • 为了结合技术和语义方面,+1。
  • 这真的为我解释了。谢谢。
【解决方案2】:

不是front 的非常量版本被调用,只是你在存储指针,然后你将它放入auto 中,它总是按值推导(而不是通过引用- -您需要auto&amp; =)。因为您正在复制 const 指针,所以您拥有自己的副本,因此 const 被省略,除非您以这种方式明确定义它。这就是为什么你要推断 TcpSocket* 而不是 TcpSocket* const

如果您想验证这一点,请尝试执行auto&amp; s = _sockets.front() 并查看您得到什么类型然后

注意。同样,由于您存储的是指针,因此您返回的 vector::const_reference 将指向 const 指针,而不是 指向 const 的指针。 p>

container 本身在该范围内是 const,这意味着您无法更改其元素序列或它们指向的内容。所以你不能说_sockets.erase(),也不能说_sockets[0]然而,由于元素本身是指向非 const TcpSocket 的指针,这意味着您几乎可以对它们做任何您想做的事情。这是你无法摆弄的容器

【讨论】:

    【解决方案3】:

    尽管std::vector&lt; TcpSocket* &gt; sockets_;它自己 const,但容器(即TcpSocket*不是 const

    这就是你得到非const 扣除的原因。

    【讨论】:

    • en.cppreference.com/w/cpp/container/vector/front -- 注意 const_referencefront() 的 const 版本返回。
    • @YamMarcovic:它返回一个指向非常量内存指针的 const 引用。
    • 这是一个比 Yam 更好的答案。它解释了真正发生的事情。
    【解决方案4】:

    为什么你没有得到TcpSocket * const:

    虽然front()返回TcpSocket* const &amp;,但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()constness 确保存储的指针不会被更改(即,您不能使 sockets_.front()Listener() 中指向另一个 TcpSocket)但保持 const-指向对象的正确性是由于用户。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-29
      • 1970-01-01
      • 2019-05-04
      • 1970-01-01
      • 2011-06-04
      • 2011-11-15
      • 1970-01-01
      相关资源
      最近更新 更多