>如果这些参数是由库定义的类型,则作为const引用传递参数的函数不能使用参数的访问函数.
>具有库定义的类型的成员对象的类不能在const函数中使用这些对象的访问函数.
克服这个问题的最佳方法是什么?最简单的解决方案是简单地从我的代码中删除所有const的使用,但这样做会非常令人沮丧.
附加信息:在这种情况下,我可以访问源代码,并且可以看到访问函数不会修改任何内容.我省略了这些信息,因为我对更一般的情况感兴趣.对于我的场景,const_cast似乎是要走的路
PS图书馆作家并不邪恶!这是一个粗略和准备好的代码,他善于开源.我可以放弃图书馆并使用其他人注意到的更专业的东西.但是,对于这个时间有限的小项目,该库接口的简单性使其成为最佳选择.
解决方法
如果它很容易辨别,而且它们没有,那么你可以const_cast你的const指针/引用非const并调用库函数.您可能希望在库类周围添加一个包装器来为您执行此操作,这样做既繁琐冗长又可以从您的类中获取该代码.这个包装器可能是一个子类,它添加了一些const访问器,这取决于你使用库类的方式是否允许它工作.
如果很难说,或者他们确实修改了东西,那么你需要在代码中使用非const实例和对库类的引用. mutable可以帮助类型(2),但对于类型(1)的那些你只需要传递非const参数.
有关它可能很难的原因的一个例子,请考虑库作者可能写了这样的东西:
struct Foo { size_t times_accessed; int value; int get() { ++times_accessed; return value; } };
现在,如果你const_cast一个Foo的const实例并调用get(),你有未定义的行为[*].因此,您必须确保实际上不会修改它所调用的对象.你可以通过确保永远不会创建任何Foo的const实例来缓解这一点,即使你确实对非const实例进行了const引用.这样,当你const_cast和调用时,至少不会导致UB.它可能会使您的代码混乱,字段会不断更改您的函数声称不会修改的对象.
[*]为什么它是未定义的行为?它必须是,语言可以保证const对象的值永远不会在有效程序中更改.这种保证允许编译器做有用的事情.例如,它可以将静态const对象放在只读数据部分中,并且可以使用已知值优化代码.它还意味着具有可见初始化程序的const整数对象是编译时常量,标准使用它来将其用作数组大小或模板参数.如果修改const对象不是UB,那么const对象将不会是常量,并且这些事情是不可能的:
#include <iostream> struct Foo { int a; Foo(int a) : a(a) {} }; void nobody_knows_what_this_does1(const int *p); // defined in another TU void nobody_knows_what_this_does2(const int *p); // defined in another TU int main() { const Foo f(1); Foo g(1); nobody_knows_what_this_does1(&f.a); nobody_knows_what_this_does2(&g.a); int x; if (std::cin >> x) { std::cout << (x / f.a); // Optimization opportunity! std::cout << (x / g.a); // Cannot optimize! } }
因为f是一个const对象,因此f.a是一个const对象,优化器知道f.a在函数末尾使用时值为1.如果它选择的话,它可以优化分裂.它对g.a不知道同样的事情:g不是const对象,指向它的指针已被传递给未知代码,因此它的值可能已经改变.因此,如果您是nobody_knows_what_this_does1或nobody_knows_what_this_does2的作者,并且您正在考虑const_casting p并使用它来修改其referand,那么只有在您以某种方式知道referand是非const时才能执行此操作.通常你不这样做,所以通常你不使用const_cast.