std::function的const正确性

11

假设我有一个可调用类型,如下所示:

struct mutable_callable
{
    int my_mutable = 0;
    int operator()() { // Not const
        return my_mutable++;
    }
};

注意,mutable_callable具有一个非const的operator(),用于修改成员变量...

现在假设我从我的类型创建一个std::function

std::function<int()> foo = mutable_callable{};

现在我可以做到这一点:

void invoke(std::function<int()> const& z)
{
    z();
}

int main()
{
    invoke(foo); // foo changed.....oops
}

据我所知,std::functionoperator()const的,如下所示: https://en.cppreference.com/w/cpp/utility/functional/function/operator()

因此,我的直觉是你不应该这样做......

但是看看这里: https://en.cppreference.com/w/cpp/utility/functional/function/function

它似乎没有对可调用类型是否具有常量operator()施加任何限制......

所以我的问题是:我正确地认为std::function<int()> const&本质上与std::function<int()>&相同,即两者的行为实际上没有区别吗?如果是这样,那么为什么不是const正确的呢?


@MaxLanghof 不是这样的.....std::function 中有一个等价于 struct a{ std::any x; }; 的东西..... - DarthRubik
以下是MSVC std::function实现的内部小片段: https://i.stack.imgur.com/eNenN.png,其中 using _Ptrt = _Func_base<_Ret, _Types...>。我已经说明了我的观点。 - Max Langhof
1个回答

4
这可以转化为与struct A { int* x; };相同的概念,其中在const A a;中,您可以修改*(a.x)的值(但不能改变指针所指向的位置)。std::function中存在一定级别的间接性(从类型擦除),通过它const无法传播。
不,std::function<int()> const& f并非毫无意义。在std::function<int()>& f中,您可以将不同的函数对象赋给f,而在const情况下则无法这样做。

嗯......那确实很有道理......不过乍一看还是有点困惑。 - DarthRubik
我认为这是一个设计缺陷。这种间接性应该是对用户透明的实现细节,而const属性可以使用一些元编程来传播。 - Igor R.
@IgorR。是的,constness可以被传播。std::vector这样做,std::unique_ptr不这样做。我觉得std::function并不真正表达函数对象状态的不变量。也许我们可以重新定义可怕的函数类型(即std::function<int() const>)来区分? - Max Langhof
unique_ptr 不应该传递 const,就像普通指针一样。而 std::function<int() const> 无法编译。 - Igor R.
1
@IgorR。我知道。我的观点是标准库的某些部分会这样做,而另一些则不会。std::function 应该属于哪个类别对我来说不是很清楚。而 std::function<int() const> 是假设性的 - 当然现在它不能编译,但如果它能够成为有效的,表达 "只能分配带有 operator() const(或无状态的)的函数对象",那么它是否能满足此处的 OP?(即使在幕后使用可怕的函数类型,这也将是相当可怕的)? - Max Langhof

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接