std::函数常量正确性未遵循
std::function const correctness not followed
我很惊讶地发现这段代码编译:
#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
?
std::function
添加了一层间接寻址,并且此间接层不会通过const
ness传递到可调用对象。
我不太确定为什么会这样——可能是因为std::function
需要可调用的副本并且不需要保留副本const
(事实上这可能会破坏赋值语义)——我也不确定为什么你需要它。
(当然,直接调用operator()
在碰巧调用Callable
并声明为const
的类型对象上调用 将需要const
上下文,就像任何其他对象一样。
最佳做法是给可调用对象一个const
operator()
,然后将其保留。
tl;DR:是的,但不是错误,也没关系
你觉得这很奇怪是正确的。std::function
的调用运算符标记为const
但在实际调用目标对象时不会传播const
性。提案 p0045r1 似乎通过将调用运算符设置为非常量但允许以下语法来解决此问题std::function
:
std::function<return_type(arg_type) const>
原因是将counter
分配给std::function
对象会创建counter
的副本。
在您的情况下,使用以下构造函数初始化f
:
template< class F >
function( F f );
如此处所述,此构造函数"使用 std::move(f) 初始化目标" - 使用copy 构造函数创建和初始化类型为Callable
的新对象。
如果要改为使用对counter
的引用来初始化f
,可以使用std::ref
:
std::function<void()> f = std::ref(counter);
std::ref
返回一个std::reference_wrapper
的实例,它有operator ()
,调用Callable
的operator () const
。正如预期的那样,您将收到一个错误,因为该运算符已删除。
- 常量函数,当其参数是对文字类型的引用时
- 为什么在C++使用常量函数时常量是多余的?
- 是否可以使用非常量指针调用非常量函数,以及当两个unique_ptrs指向同一个对象时程序的行为方式?
- 为什么在PIMPL中无法访问实现类的常量函数?
- 常量函数参数的专业化
- 如何调用非常量函数而不是常量函数?
- 常量和非常量函数作为模板参数参数
- 通过引用常量函数调用另一个类的非常量函数
- C++编译器如何检测非常量函数体
- 使用常量函数返回常量引用时出现奇怪的行为
- 常量字符数组模板与字符常量* 函数重载
- 现代C++编译器是否能够避免在某些条件下两次调用常量函数
- 将函数声明为 GCC 纯函数或常量函数的效果(当它不是时)
- 为什么常量/非常量函数重载的继承不明确
- 类型定义模板,接受指向常量和非常量函数的指针
- 如何避免语法相同的常量和非常量函数之间代码重复,这些函数在语义上不相同
- 继承的常量函数
- 不确定 c++ 中的常量函数是什么
- 在常量函数中使用安全的非常量函数
- c++如何定义其他开发人员需要调用的常量函数顺序