【问题标题】:std::function const correctness not followed未遵循 std::function const 正确性
【发布时间】:2018-10-30 10:49:52
【问题描述】:

我惊讶地发现这段代码可以编译:

#include <functional>

struct Callable {
    void operator() () { count++; }
    void operator() () const = delete;
    int count = 0;
};

int main() {
    const Callable counter;
    // counter(); //error: use of deleted function 'void Callable::operator()() const'
    std::function<void(void)> f = counter;
    f();

    const auto cf = f;
    cf();

}

https://wandbox.org/permlink/FH3PoiYewklxmiXl

这将调用Callable 的非常量调用运算符。相比之下,如果您执行const auto cf = counter; cf();,那么它会按预期出错。那么,为什么 std::function 似乎没有遵循 const 正确性?

【问题讨论】:

  • 我认为你对什么是 const 什么不是。你的声明没有使counter const,它是具有const=delete 的那个。
  • 为什么会调用const 版本?

标签: c++ constants std-function


【解决方案1】:

std::function增加了一层间接,这层间接不通过constness到callable。

我不太确定为什么会这样——可能是因为 std::function 获取了可调用的副本并且不需要保留副本 const(实际上这可能会破坏赋值语义)——我也不是非常确定您为什么需要它。

(当然,直接在您碰巧调用Callable 并声明为const 的类型的对象上调用operator() 将需要const 上下文,就像使用任何其他对象一样。 )

最佳做法是给可调用对象一个 const operator() 并保留它。

tl;dr: 是的,但不是错误,没关系

【讨论】:

    【解决方案2】:

    你觉得这很奇怪是对的。 std::function 的调用运算符标记为 const,但在实际调用目标对象时不会传播 constness。 p0045r1 提案似乎通过使 std::function 的调用运算符为非 const 但允许以下语法来解决此问题:

    std::function<return_type(arg_type) const>
    

    【讨论】:

      【解决方案3】:

      原因是将counter 分配给std::function 对象会创建counter 的副本。

      在您的情况下,f 使用以下构造函数进行初始化:

      template< class F >
      function( F f );
      

      here 所述,此构造函数“使用std::move(f) 初始化目标” - 使用复制构造函数创建并初始化Callable 类型的新对象。 p>

      如果您想使用 counter 的引用来初始化 f,则可以使用 std::ref

      std::function<void()> f = std::ref(counter);
      

      std::ref返回一个std::reference_wrapper的实例,它有operator (),它调用Callableoperator () const。正如预期的那样,您会收到一个错误,因为该运算符已被删除。

      【讨论】:

        猜你喜欢
        • 2020-03-29
        • 2022-01-10
        • 2022-08-04
        • 2011-05-06
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多