我经常发现自己必须定义一个函数的两个版本,以便拥有一个 const 版本和一个非常量版本(通常是 getter,但并非总是如此)。两者的区别仅在于,其中一个的输入和输出是常量,而另一个的输入和输出是非常量。该功能的核心——真正的工作,是相同的。
然而,为了常量正确性,我需要它们两者。作为一个简单的实际示例,请看以下内容:
inline const ITEMIDLIST * GetNextItem(const ITEMIDLIST * pidl)
{
return pidl ? reinterpret_cast<const ITEMIDLIST *>(reinterpret_cast<const BYTE *>(pidl) + pidl->mkid.cb) : NULL;
}
inline ITEMIDLIST * GetNextItem(ITEMIDLIST * pidl)
{
return pidl ? reinterpret_cast<ITEMIDLIST *>(reinterpret_cast<BYTE *>(pidl) + pidl->mkid.cb) : NULL;
}
正如你所看到的,他们做同样的事情。我可以选择使用更多的强制转换来根据另一个来定义一个,如果胆量 - 实际工作,不那么微不足道,那么这是更合适的:
inline const ITEMIDLIST * GetNextItem(const ITEMIDLIST * pidl)
{
return pidl ? reinterpret_cast<const ITEMIDLIST *>(reinterpret_cast<const BYTE *>(pidl) + pidl->mkid.cb) : NULL;
}
inline ITEMIDLIST * GetNextItem(ITEMIDLIST * pidl)
{
return const_cast<ITEMIDLIST *>(GetNextItem(const_cast<const ITEMIDLIST *>(pidl));
}
所以,我觉得这非常乏味和多余。但是,如果我希望编写 const 正确的代码,那么我要么必须提供上述两者,要么必须用 const 强制转换来乱扔我的“消费者代码”,以解决仅定义一个或另一个的问题。
有更好的模式吗?您认为解决此问题的“最佳”方法是什么:
- 提供给定函数的两个副本 - const 和非 const 版本
- 或者只是一个版本,然后要求该代码的使用者按照他们的意愿进行转换?
或者有更好的方法来解决这个问题吗?
语言本身是否正在做一些工作来减轻或完全消除这个问题?
对于奖励积分:
- 您是否认为这是 C++ const 系统的一个不幸的副产品
- 或者你认为这相当于触及奥林匹斯山的高度吗?
EDIT:
如果我只提供第一个 - 接受 const 返回 const,那么任何需要修改返回项或将返回项传递给另一个将修改它的函数的消费者都必须摆脱常量性。
类似地,如果我只提供第二个定义 - 接受非 const 并返回非 const,那么具有 const pidl 的使用者必须放弃 constness 才能使用上述函数,老实说,这不会修改 constness物品本身。
也许更多的抽象是可取的:
THING & Foo(THING & it);
const THING & Foo(const THING & it);
我很想有一个构造:
const_neutral THING & Foo(const_neutral THING & it);
我当然可以做这样的事情:
THING & Foo(const THING & it);
但这总是让我感到不舒服。我的意思是“我不会修改你的东西的内容,但我会在你的代码中去掉你默默委托给我的常量。”
现在,一个客户,其中有:
const THING & it = GetAConstThing();
...
ModifyAThing(Foo(it));
那是错误的。 GetAConstThing 与调用者的约定是给它一个 const 引用。调用者不应修改该事物 - 仅对其使用 const 操作。是的,调用者可能是邪恶的、错误的,并且抛弃了它的恒定性,但这只是邪恶(tm)。
对我来说,问题的关键在于 Foo 是常量中立的。它实际上并不修改其给定的内容,但其输出需要传播其参数的常量性。
注意:第二次编辑格式。